bzoj 2594 水管局长 | LCT | 最小生成树
2015-11-16 10:39
302 查看
将所有操作逆序,删边就成了加边,做LCT维护最小生成树即可。把边i表示成点i+n,那么加一条边x,y就相当于link(x,i+n) link(y,i+n) 删边同理。我的release写成了“上放标记”了 TAT
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #define md #define ll long long #define inf (int) 1e9 #define eps 1e-8 #define N 2000010 using namespace std; struct yts { int x,y,l,id,del;} e ; struct QQ { int x,y,pos,opt;} q[200010]; int father ; int n,m; int ch [2],fa ,rev ,mx ,po ,dt ,que ; int ans[100010]; int read() { char ch = getchar(); for ( ; ch > '9' || ch < '0'; ch = getchar()); int tmp = 0; for ( ; '0' <= ch && ch <= '9'; ch = getchar()) tmp = tmp * 10 + int(ch) - 48; return tmp; } bool cmpid(yts a,yts b) { return a.id<b.id;} bool cmp(yts a,yts b) { return a.l<b.l; } bool operator < (yts a,yts b) { return a.x==b.x?a.y<b.y:a.x<b.x; } int find_path(int x,int y) { yts nd; nd.x=x; nd.y=y; int l=1,r=m; while (l!=r) { int mid=(l+r)>>1; if (e[mid]<nd) l=mid+1; else r=mid; } return l; } int find(int x) { return father[x]==x?x:father[x]=find(father[x]);} //----------------------------------------------------------------- bool isroot(int x) { if (ch[fa[x]][0]==x||ch[fa[x]][1]==x) return 0; else return 1; } bool dir(int x) { return ch[fa[x]][1]==x;} void release(int i) { if (rev[i]) { rev[i]=0; swap(ch[i][0],ch[i][1]); if (ch[i][0]) rev[ch[i][0]]^=1; if (ch[i][1]) rev[ch[i][1]]^=1; } } void update(int i) { int l=ch[i][0],r=ch[i][1]; mx[i]=dt[i]; po[i]=i; if (l&&mx[i]<mx[l]) { mx[i]=mx[l]; po[i]=po[l]; } if (r&&mx[i]<mx[r]) { mx[i]=mx[r]; po[i]=po[r]; } } void rotate(int x) { int y=fa[x],z=fa[y],b=dir(x),c=dir(y),a=ch[x][!b]; if (!isroot(y)) ch[z][c]=x; if (a) fa[a]=y; fa[y]=x; fa[x]=z; ch[x][!b]=y; ch[y][b]=a; update(y); update(x); } void splay(int x) { int w=0; que[++w]=x; for (int i=x;!isroot(i);i=fa[i]) que[++w]=fa[i]; for (int i=w;i;i--) release(que[i]); while (!isroot(x)) { int y=fa[x],z=fa[y]; if (isroot(y)) rotate(x); else { if (dir(x)==dir(y)) { rotate(y); rotate(x); } else { rotate(x); rotate(x); } } } } void access(int x) { int t=0; while (x) { splay(x); ch[x][1]=t; update(x); t=x; x=fa[x]; } } void makeroot(int x) { access(x); splay(x); rev[x]^=1; } void link(int x,int y) { makeroot(x); fa[x]=y; } void cut(int x,int y) { makeroot(x); access(y); splay(y); fa[x]=ch[y][0]=0; update(x); update(y); } int query(int x,int y) { makeroot(x); access(y); splay(y); return po[y]; } //----------------------------------------------------------------- int main() { //freopen("data.in","r",stdin); freopen("data.out","w",stdout); int Q; n=read(),m=read(),Q=read(); for (int i=1;i<=n;i++) dt[i]=mx[i]=0; for (int i=1;i<=m;i++) { e[i].x=read(); e[i].y=read(); e[i].l=read(); if (e[i].x>e[i].y) swap(e[i].x,e[i].y); e[i].id=i; dt[i+n]=mx[i+n]=e[i].l; } sort(e+1,e+m+1); for (int i=1;i<=Q;i++) { int opt=read(),x=read(),y=read(); if (x>y) swap(x,y); if (opt==1) { q[i].x=x; q[i].y=y; q[i].opt=1; } else { int p=find_path(x,y); e[p].del=1; q[i].x=x; q[i].y=y; q[i].opt=2; q[i].pos=e[p].id; } } sort(e+1,e+m+1,cmp); for (int i=1;i<=n;i++) father[i]=i; for (int i=1;i<=m;i++) { if (e[i].del) continue; int x=e[i].x,y=e[i].y; int f1=find(x),f2=find(y); if (f1!=f2) { father[f1]=f2; int p=e[i].id; link(x,p+n); link(y,p+n); } } sort(e+1,e+m+1,cmpid); int ww=0; for (int i=Q;i;i--) { if (q[i].opt==1) ans[++ww]=dt[query(q[i].x,q[i].y)]; else { int id=q[i].pos,x=q[i].x,y=q[i].y; int p=query(x,y); if (dt[p]>e[id].l) { cut(x,p); cut(y,p); link(x,id+n); link(y,id+n); } } } for (int i=ww;i;i--) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- bzoj 3706 反色刷 | 一笔画
- bzoj 3108 图的逆变换
- bzoj 2660 最多的方案 | 斐波那契数列
- bzoj 1187 神奇的游乐园 | 插头dp
- bzoj 2173 整数的lqp拆分 | dp | 找规律
- poj 2411| 插头dp
- bzoj 2660 最多的方案 | dp
- bzoj 3170 松鼠聚会 | 旋转坐标
- bzoj 1537 bus|cdq分治
- bzoj 2257 瓶子和燃料
- bzoj 3398 牡牛和牝牛
- bzoj 3534 重建
- bzoj 4017 小Q的无敌异或
- bzoj 1002 轮状病毒
- bzoj 3288 矩阵
- bzoj 4031 小z的房间
- bzoj 4004 装备购买
- 容斥原理
- 主席树&树状数组套主席树
- bzoj 3589 动态树