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