P2387 NOI2014 魔法森林(LCT)

2021-09-22 21:39:41 字數 1532 閱讀 8097

將所有邊按a從小到大排序,加入一條新邊(u,v)時,檢查原先u和v是否連通,若連通則斷開舊路徑,新路徑上最大的b和新加入的邊的a相加,看能否更新答案。

既然是動態加邊和刪邊,便考慮用lct。要查詢兩點間路徑上的最大值,所以點和邊都要建節點,並且維護最大的b和其對應的邊的標號。當加入新邊檢查是否兩點已聯通時,先把b最大的邊斷開再連線新邊,但如果已經聯通且舊路徑上最大值小於新邊的值,就不用再試新邊了。

單獨判一下自環吧。至少我這種標號方式的話是必須判的。

#include#include#includeusing namespace std;

const int n=200010,m=100010,inf=20000000;

struct edgedata[m];

struct nodetree[n];

int n,m,ans,q[n],f[n];

inline int read()

while(ch>='0'&&ch<='9')

return f?-x:x;

}int getfa(int x)

bool cmp(edge i,edge j)

if(tree[tree[p].r].m>tree[p].m)

}inline bool nroot(int p)

inline void left_rotate(int p)

tree[q].fa=p;tree[p].l=q;tree[p].fa=r;

update(q);update(p);

}inline void right_rotate(int p)

tree[q].fa=p;tree[p].r=q;tree[p].fa=r;

update(q);update(p);

}inline bool getlr(int p)

inline void rotate(int p)

inline void splay(int p)rotate(p); }}

inline void access(int p)

}inline void makeroot(int p)

inline int split(int x,int y)

inline void link(int x,int y)

inline void cut(int x,int y)

int main()

sort(data+1,data+m+1,cmp);

for(int i=1;i<=n;i++)f[i]=i;

ans=inf;bool flag=false;

for(int i=1;i<=n;i++)

for(int xx,yy,i=1;i<=m;i++)

} else

if(!flag&&getfa(1)==getfa(n))flag=true;

if(flag)

} if(ans==inf)printf("-1");

else printf("%d",ans);

return 0;

}

P2387 NOI2014 魔法森林

p2387 noi2014 魔法森林 這題目花了點時間題解沒圖,其中一些操作不夠簡潔,常數比較大,都說 lct 常數小 時限 3000ms 最大點 500ms 反正過了 首先考慮做法 排序 a 順序加邊,然後動態維護最大 b 使生成樹最小,其中貢獻為最大的 b 這題是動態的,所以考慮 lct 但不同...

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 小,加了肯定不優,否則就把那條邊斷掉,加上這...