HNOI2018排列(堆 並查集)

2021-09-11 18:47:49 字數 3689 閱讀 9868

題目鏈結

給定數列a(0

≤ai≤

n)

a(0\le a_i\le n)

a(0≤ai

​≤n)

,設其排列後的數列為ap1

,ap2

,...

,apn

a_,a_,...,a_

ap1​​,

ap2​

​,..

.,ap

n​​,要求對於任意的k

kk,滿足1≤j

≤k,a

pj≠p

k1\le j\le k,a_\neq p_k

1≤j≤k,

apj​

​̸​=

pk​。某個合法排列的價值為wp1

+2wp

2+..

.+nw

pn

w_+2w_+...+nw_

wp1​​+

2wp2

​​+.

..+n

wpn​

​,求最大價值。

n ≤5

×105

n\le 5\times 10^5

n≤5×10

5神題qaq。

首先,好好思考題目中那個亂七八糟的條件是啥,也就是說讓=pk

=p_k

=pk​

的a

aa值出現在第k

kk個之後。我們考慮最後p

pp的排列方式,顯然對於任意a

ia_i

ai​,使=ai

=a_i

=ai​

的p

pp值出現在=i=i

=i的p

pp值之前。

於是我們就得到了若干個限制p

pp數列的關係,於是對於每個a

ia_i

ai​,從a

ia_i

ai​向i

ii連一條邊,得到了乙個圖。如果這個圖中存在環的話顯然無解,否則這個圖就是以0為根的樹。

考慮w

ww最小的那個點,顯然如果它的father被選了,下乙個選的必然是它。因此它倆必然在數列中連續,於是把它們用並查集合起來,計算貢獻。

然而這樣操作之後就變成了多個連通塊比較,我們如何選擇最小的連通塊呢?

考慮任意兩個連通塊a,b

a,ba,

b,如果a

aa在b

bb之前更優,則必然有siz

e[a]

⋅sum

[b]+

sum[

a]+s

um[b

]>su

m[a]

⋅siz

e[b]

+sum

[a]+

sum[

b]

size[a]\cdot sum[b]+sum[a]+sum[b]>sum[a]\cdot size[b]+sum[a]+sum[b]

size[a

]⋅su

m[b]

+sum

[a]+

sum[

b]>su

m[a]

⋅siz

e[b]

+sum

[a]+

sum[

b],消一下就變成了siz

e[a]

⋅sum

[b

]>si

ze[b

]⋅su

m[a]

size[a]\cdot sum[b]>size[b]\cdot sum[a]

size[a

]⋅su

m[b]

>si

ze[b

]⋅su

m[a]

。於是用優先佇列維護最小值就行了,複雜度o(n

logn

)o(nlogn)

o(nlog

n)。

#include

namespace iostream

template

<

typename t>

inline

void

read

(t &x)

template

<

typename t1,

typename..

.t2>

inline

void

read

(t1 &a, t2&..

. x)

inline

intreads

(char

*s)inline

void

ioflush()

inline

void

printc

(char c)

inline

void

prints

(const

char

*s,char c)

template

<

typename t>

inline

void

print

(t x,

char c =

'\n'

)else

printc

('0');

printc

(c);

}template

<

typename t1,

typename..

.t2>

inline

void

print

(t1 x, t2.

.. y)

}using

namespace iostream;

using

namespace std;

typedef

long

long ll;

typedef pair<

int,

int> p;

const

int maxn =

500005

;struct node };

priority_queue pq;

int ww[maxn]

, par[maxn]

, sz[maxn]

, fa[maxn]

, n;

ll sum[maxn]

;int

find

(int x)

void

merge

(int x,

int y)

intmain()

ll res =0;

for(

int i =

1; i <= n; i++))

;}par[0]

=0, sz[0]

=1;for

(int i =

1; i <= n; i++

)int p =

find

(fa[d.rt]);

res +

= sum[d.rt]

* sz[p]

;merge

(d.rt, p)

; pq.

push

((node));

}printf

("%lld\n"

, res)

;return0;

}

BZOJ5289 貪心 HNOI2018 排列

bzoj5289 膜了一下pipiboss的題解 我覺得我自己描述的都沒有他好 所以就貼吧 首先注意到實際上約束關係構成了一棵樹 考慮這個排列 pp,編號為 a i a i 的出現了,ii 才可以出現 那麼如果連邊 a i i a i i 就會構成一棵以 00 為根的樹,每乙個點只有乙個父親 否則就...

心情 HNOI2018遊記

day 0.全機房的人好像都在做題。然而下午是社團節的遊園會,身為社幹的我風風雨雨在外面各種搬凳子搬椅子換場地招待外校同學 就這樣我好像什麼都沒有複習。晚上就一起去酒店了。大概因為是高一的緣故,並沒有非常的緊張。住進了酒店,滿腦子都是和豆豆 ww3113306 如何吃吃吃玩玩玩。非常開心的擺了一晚上...

比賽 HNOI2018 總結

一將功成萬骨枯,我就是給那些隊爺做基數的 看完題,暴力好打,然後就打 覺得第三題模型很好建啊,先看第三題吧 結果第三題是最。的 圖建出來,先看樹的情況,設dp試一下 結果一直只想著一維的dp,沒去想0 1狀態表示是否選取,於是老久都沒想出來 第一題一開始沒看到30分的狀壓,突然看到,然後就趕緊碼一下...