1. 程式人生 > >BZOJ 2594 [Wc2006]水管局長資料加強版 LCT

BZOJ 2594 [Wc2006]水管局長資料加強版 LCT

題意:連結

方法: LCT

解析:

搞了一個上午加1個小時的題,TM最後大錯誤居然是排序元素太多排不回原來的樣子!

我要重新學排序!

這題是用LCT維護動態最小生成樹,但是最小生成樹上刪邊應該是做不到的,所以我們可以離線操作,之後先把所有該刪的邊刪瞭然後倒著搞所有詢問,這樣刪邊就變成了加邊,之後詢問就是x到y路徑上的最大邊權。

圖是動態的,所以想到LCT,但是LCT不能搞最大邊權怎麼辦!

把每個邊看做一個點。

假設這是第i個邊,那麼把他看做第i+n個點。

顯然點權就是邊權,然後將這個邊連線的兩個點分別與我們視作的點進行連邊就OK了,也不難。

然後剩下的部分就是細節問題了。比如什麼查詢邊之類的,也挺好寫。

唯一的忠告就是!排序一定要寫好cmp!

程式碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1000010
#define Q 100010
#define N 1100010
using namespace std;
int n,m,q;
int fffa[N];
int mx[N],ch[N][2],fa[N],rt[N],val[N],the_no_of_the_max[N];
int rev[N];
struct node
{
    int
from,to,val,addtag,id; }edge[M]; struct query { int opt,from,to,ans,id; }que[Q]; void pushup(int x) { if(!x)return; mx[x]=val[x]; the_no_of_the_max[x]=x; if(ch[x][0]!=0&&mx[ch[x][0]]>mx[x])mx[x]=mx[ch[x][0]],the_no_of_the_max[x]=the_no_of_the_max[ch[x][0]]; if(ch[x][1
]!=0&&mx[ch[x][1]]>mx[x])mx[x]=mx[ch[x][1]],the_no_of_the_max[x]=the_no_of_the_max[ch[x][1]]; } void reverse(int x) { if(!x)return; swap(ch[x][0],ch[x][1]); rev[x]^=1; } void pushdown(int x) { if(rev[x]) { if(ch[x][0]!=0) reverse(ch[x][0]); if(ch[x][1]!=0) reverse(ch[x][1]); rev[x]=0; } } void down(int x) { if(!x)return; if(!rt[x])down(fa[x]); pushdown(x); } void rotate(int x) { if(!x)return; int y=fa[x],kind=ch[y][1]==x; ch[y][kind]=ch[x][!kind]; fa[ch[y][kind]]=y; ch[x][!kind]=y; fa[x]=fa[y]; fa[y]=x; if(rt[y])rt[y]=0,rt[x]=1; else ch[fa[x]][ch[fa[x]][1]==y]=x; pushup(y); } void splay(int x) { if(!x)return; down(x); while(!rt[x]) { int y=fa[x],z=fa[y]; if(rt[y])rotate(x); else if((ch[y][1]==x)==(ch[z][1]==y))rotate(y),rotate(x); else rotate(x),rotate(x); } pushup(x); } void access(int x) { if(!x)return; int y=0; while(x) { splay(x); rt[ch[x][1]]=1,rt[y]=0; ch[x][1]=y; pushup(x); y=x,x=fa[x]; } } void movetoroot(int x) { if(!x)return; access(x); splay(x); reverse(x); } void link(int x,int y) { if(!x)return; movetoroot(x); fa[x]=y; } void cut(int x,int y) { if(!x)return; movetoroot(x); access(y); splay(y); ch[y][0]=0; fa[x]=0; rt[x]=1; pushup(y); } int cmp1(node a,node b) { if(a.val==b.val) { if(a.from==b.from)return a.to<b.to; return a.from<b.from; } return a.val<b.val; } int cmp2(node a,node b) { if(a.from==b.from)return a.to<b.to; return a.from<b.from; } bool operator < (node a,node b) { if(a.from==b.from)return a.to<b.to; return a.from<b.from; } int find(int x,int y) { int ret; node tmp; tmp.from=x,tmp.to=y,tmp.val=0,tmp.addtag=0; ret=lower_bound(edge+1,edge+m+1,tmp)-edge; return ret; } int findfa(int x) { if(fffa[x]!=x)return fffa[x]=findfa(fffa[x]); return x; } inline int Get_Int() { int x=0,f=1;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; } void init() { for(int i=1;i<=n+m;i++) { fffa[i]=i; } memset(val,0,sizeof(val)); for(int i=1;i<=n+m;i++) { rt[i]=1,the_no_of_the_max[i]=i; } } int main() { n=Get_Int(),m=Get_Int(),q=Get_Int(); init(); for(int i=1;i<=m;i++) { edge[i].from=Get_Int(),edge[i].to=Get_Int(),edge[i].val=Get_Int(); if(edge[i].from>edge[i].to) { swap(edge[i].from,edge[i].to); } } sort(edge+1,edge+1+m,cmp1); for(int i=1;i<=m;i++) { edge[i].id=i; val[i+n]=edge[i].val; mx[i+n]=edge[i].val; the_no_of_the_max[i+n]=i+n; } sort(edge+1,edge+1+m,cmp2); for(int i=1;i<=q;i++) { que[i].opt=Get_Int(),que[i].from=Get_Int(),que[i].to=Get_Int(); if(que[i].from>que[i].to) swap(que[i].from,que[i].to); if(que[i].opt==2) { int no=find(que[i].from,que[i].to); edge[no].addtag=1; que[i].id=edge[no].id; } } sort(edge+1,edge+1+m,cmp1); int the_number_of_the_edges_which_have_been_chosen=0; for(int i=1;i<=m;i++) { if(edge[i].addtag==1)continue; int x=edge[i].from,y=edge[i].to; int fx=findfa(x),fy=findfa(y); if(fx!=fy) { the_number_of_the_edges_which_have_been_chosen++; fffa[fx]=fy; link(x,i+n),link(i+n,y); if(the_number_of_the_edges_which_have_been_chosen==n-1)break; } } for(int i=q;i>=1;i--) { if(que[i].opt==1) { int x=que[i].from,y=que[i].to; movetoroot(x); access(y); splay(y); que[i].ans=mx[y]; }else { int x=que[i].from,y=que[i].to; movetoroot(x); access(y); splay(y); int t=the_no_of_the_max[y]; int tmpt=que[i].id; if(edge[tmpt].val<val[t]) { cut(edge[t-n].from,t),cut(t,edge[t-n].to); link(x,tmpt+n),link(tmpt+n,y); } } } for(int i=1;i<=q;i++) { if(que[i].opt==1) printf("%d\n",que[i].ans); } }