P2387 NOI2014 魔法森林

2022-05-20 20:13:08 字數 1460 閱讀 2326

p2387 [noi2014]魔法森林

這題目花了點時間題解沒圖,其中一些操作不夠簡潔,常數比較大,都說\(lct\)常數小(時限\(3000ms\),最大點\(500ms\)),反正過了

首先考慮做法:排序\(a\),順序加邊,然後動態維護最大\(b\)(使生成樹最小,其中貢獻為最大的\(b\))

這題是動態的,所以考慮\(lct\),但不同的是維護邊權,根據我們圖論的技巧,把邊轉點(拆成三點\(u,x,v\)),其中\(x\)存下邊權

我們在添邊的時候,如果不構成環(\(u,v\)實現沒聯通)之間添進去,構成環就利用\(lct\)把這個環最大的\(b\)提出來跟這條邊比然後替換

添邊\((u,x,v)\):\(u\)和\(v\)分別拉成各自聯通塊的子樹,然後\(u-x-v\)輕邊連起來

刪邊\((u,x,v)\):\(u,v\)拉鍊,中間就只剩下\(x\)了嘛,\(x\)提到根然後刪掉

總結一下:貪心+\(lct\)動態維護最大權邊

#include#include#include#include#include#include#includeusing namespace std;

typedef int ll;

const ll maxn=1e6,b=(1<<17),inf=0x3f3f3f3f;

inline ll read()

while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();

return x*f;

}struct e

inline bool notroot(ll x)

inline void pushr(ll x)

inline void pushdown(ll x)

}inline void rotate(ll x)

inline void splay(ll x)rotate(x); }}

inline void access(ll x)

inline void makeroot(ll x)

inline void split(ll x,ll y)

inline ll findroot(ll x)

inline void link(ll x)

inline void delet(ll x)

int main();

dis[i].u|=b,dis[i].v|=b;

} sort(dis+1,dis+1+m);

for(ll i=1;i<=m;++i)

} makeroot(1|b);

if((1|b)==findroot(n|b))

ans=min(ans,dis[i].a+dis[mx[n|b]].b);

} if(ansprintf("%d\n",ans);

else

printf("-1");

return 0;

}

P2387 NOI2014 魔法森林(LCT)

將所有邊按a從小到大排序,加入一條新邊 u,v 時,檢查原先u和v是否連通,若連通則斷開舊路徑,新路徑上最大的b和新加入的邊的a相加,看能否更新答案。既然是動態加邊和刪邊,便考慮用lct。要查詢兩點間路徑上的最大值,所以點和邊都要建節點,並且維護最大的b和其對應的邊的標號。當加入新邊檢查是否兩點已聯...

P2387 NOI2014 魔法森林(LCT)

p2387 noi2014 魔法森林 lct邊權維護經典題 咋維護呢?邊化為點,邊權變點權。本題中我們把邊對關鍵字a進行排序,動態維護關鍵字b的最小生成樹 加邊後出現環咋辦?splay維護最大邊的編號,找到最大邊刪除再加新邊就ok辣 include include using namespace s...

luogu P2387 NOI2014 魔法森林

傳送門 這題似乎不好直接做,可以考慮按照 a i 公升序排序,然後依次加邊更新答案 具體實現方法是用lct維護當前的樹,這裡需要維護鏈上最大的 b i 每次加一條邊,如果加完以後沒有環直接加,否則找出鏈上最大的 b i 如果這個 b i 比當前的 b i 小,加了肯定不優,否則就把那條邊斷掉,加上這...