bzoj 2594
很好的一道LCT題目
首先我們可以發現,題目要求的就是最小生成樹上的一條樹鏈的最長邊的長度,因此我們實際只需動態維護最小生成樹即可
然后我們考慮怎么動態維護最小生成樹
不難發現,如果涉及在最小生成樹上刪邊,那么這個操作將變得非常復雜,因為我們并不知道刪邊之后要把什么樣的邊補充回去才行
但是,如果我們倒序操作,把刪邊變成加邊,那么這個操作就變得相對簡單了
回到本題,首先,我們把一定不會刪的邊建成一棵最小生成樹(或者一個森林?),這就是我們的初始狀態
然后,倒序操作,每次把刪邊變為加邊,這樣每次加入一條邊時,我們只需討論這兩個點原先是否聯通即可
如果兩個點原先就聯通,那么我們就找到這兩個點所在聯通塊里邊權最大的邊,刪去那條邊之后加入這條新來的邊即可
但是LCT難以維護邊權,因此我們對每條邊虛擬一個有點權的點,加邊時把邊的兩個端點連到這個點上即可
刪邊同理
注意維護邊的編號
貼代碼:
(這個東西由于常數過于巨大在bzoj上過不去,但是luogu上的數據減弱版能過)
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <map> using namespace std; struct Ques { int x,y,typ,num; }q[1000005]; struct Edge { int l,r,v; friend bool operator < (Edge a,Edge b) { return a.v<b.v; } }edge[1000005]; map <pair<int,int>,int> M; int n,m,Q; int ch[2000005][2]; int vis[2000005]; int maxx[2000005]; int val[2000005]; int f[2000005]; int fl[2000005]; int ret[2000005]; void update(int x) { maxx[x]=val[x]; if(edge[maxx[ch[x][0]]].v>edge[maxx[x]].v)maxx[x]=maxx[ch[x][0]]; if(edge[maxx[ch[x][1]]].v>edge[maxx[x]].v)maxx[x]=maxx[ch[x][1]]; } bool be_root(int x) { if(ch[f[x]][0]==x||ch[f[x]][1]==x)return 0; return 1; } void pushdown(int x) { if(fl[x]) { swap(ch[ch[x][0]][0],ch[ch[x][0]][1]); swap(ch[ch[x][1]][0],ch[ch[x][1]][1]); fl[ch[x][0]]^=1,fl[ch[x][1]]^=1; fl[x]=0; } } void repush(int x) { if(!be_root(x))repush(f[x]); pushdown(x); } void rotate(int x) { int y=f[x],z=f[y],k=(ch[y][1]==x); if(!be_root(y))ch[z][ch[z][1]==y]=x; f[x]=z; ch[y][k]=ch[x][!k],f[ch[x][!k]]=y; ch[x][!k]=y,f[y]=x; update(y),update(x); } void splay(int x) { repush(x); while(!be_root(x)&&x) { int y=f[x],z=f[y]; if(!be_root(y)&&y) { if((ch[y][1]==x)^(ch[z][1]==y))rotate(x); else rotate(y); } rotate(x); } update(x); } void access(int x) { int y=0; while(x) { splay(x); ch[x][1]=y; update(x); y=x,x=f[x]; } } void makeroot(int x) { access(x),splay(x); swap(ch[x][0],ch[x][1]),fl[x]^=1; } void link(int x,int y) { makeroot(x); f[x]=y; } void split(int x,int y) { makeroot(x),access(y),splay(y); } void cut(int x,int y) { split(x,y),ch[y][0]=f[x]=0,update(y); } int findf(int x) { access(x),splay(x),pushdown(x); while(ch[x][0])x=ch[x][0],pushdown(x); return x; } inline int read() { int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main() { n=read(),m=read(),Q=read(); for(int i=1;i<=m;i++) { edge[i].l=read(),edge[i].r=read(),edge[i].v=read(); if(edge[i].l>edge[i].r)swap(edge[i].l,edge[i].r); } sort(edge+1,edge+m+1); for(int i=1;i<=m;i++)M[make_pair(edge[i].l,edge[i].r)]=i; for(int i=1;i<=Q;i++) { q[i].typ=read(),q[i].x=read(),q[i].y=read(); if(q[i].x>q[i].y)swap(q[i].x,q[i].y); if(q[i].typ==2) { int t=M[make_pair(q[i].x,q[i].y)]; q[i].num=t,vis[t]=1; } } for(int i=1;i<=m;i++)maxx[i+n]=val[i+n]=i; for(int i=1;i<=m;i++) { if(vis[i])continue; int f1=findf(edge[i].l),f2=findf(edge[i].r); if(f1==f2)continue; link(edge[i].l,i+n),link(edge[i].r,i+n); } int temp=Q; while(Q) { if(q[Q].typ==1) { split(q[Q].x,q[Q].y); ret[Q]=edge[maxx[q[Q].y]].v; }else { split(q[Q].x,q[Q].y); int t=maxx[q[Q].y]; if(edge[q[Q].num].v<edge[maxx[q[Q].y]].v) { cut(edge[t].l,t+n); cut(edge[t].r,t+n); link(edge[q[Q].num].l,q[Q].num+n); link(edge[q[Q].num].r,q[Q].num+n); } } Q--; } for(int i=1;i<=temp;i++)if(q[i].typ==1)printf("%d\n",ret[i]); return 0; }

浙公網安備 33010602011771號