NKOJ 2698 Nicole的博客 (动态树+最小生成树)
2017-12-01 20:17
302 查看
P2698【动态树】Nicole的博客
问题描述给你一个由N个节点M条带权边构成的无向简单图,然后进行Q次操作:
·1 x y :询问一条连接x,y的路径,使路径上权值最大的边权值最小;
·2 x y :删除原本连接x,y的边,保证这条边存在。
对每次询问,输出路径上权值最大的边的权值。
输入格式
第一行三个数N,M,Q
接下来M行每行三个数x,y,z,表示有一条连接x,y的边,权值为z
接下来Q行,每行k,x,y,表示一次操作
输出格式
对每次询问输出一行
样例输入
4 4 3
1 2 2
2 3 3
3 4 2
1 4 2
1 1 4
2 1 4
1 1 4
样例输出
2
3
提示
1<=N<=100000
1<=M<=1000000
1<=Q<=100000
1<=x,y<=N
1<=z<=109
保证任意时刻整个图连通
由询问可知,显然维护一颗最小生成树,然后考虑操作二,删边,不好操作。
考虑离线,显然倒序讨论,那么删边变成加边,用LCT维护这颗最小生成树,直接搞就好。
关于处理边权,将边变成点,然后往两个端点连边即可转化成点权。
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #define N 2000005 using namespace std; struct node{int x,y,z,id;bool f;}edge ; bool cmp1(node a,node b) {return a.z<b.z;} bool cmp2(node a,node b) { if(a.x==b.x)return a.y<b.y; return a.x<b.x; } int n,m,q,top,S ,F ,Hash ; int ty ,A ,B ,Ans ; int ls ,rs ,fa ,Max ,id ,v ,rev ; int GM(int x,int y,int z) { if(x>=y&&x>=z)return x; if(y>=z)return y; return z; } bool Isroot(int x) {return ls[fa[x]]!=x&&rs[fa[x]]!=x;} void MT(int p) { Max[p]=GM(v[p],Max[ls[p]],Max[rs[p]]); if< 101b9 /span>(Max[p]==v[p])id[p]=p; else if(Max[p]==Max[ls[p]])id[p]=id[ls[p]]; else id[p]=id[rs[p]]; } void PD(int p) { if(rev[p]) { swap(ls[p],rs[p]); rev[ls[p]]^=1; rev[rs[p]]^=1; rev[p]^=1; } } void Zig(int x) { int y=fa[x],z=fa[y]; if(!Isroot(y))y==ls[z]?ls[z]=x:rs[z]=x;fa[x]=z; ls[y]=rs[x];fa[rs[x]]=y; rs[x]=y;fa[y]=x; MT(y);MT(x); } void Zag(int x) { int y=fa[x],z=fa[y]; if(!Isroot(y))y==ls[z]?ls[z]=x:rs[z]=x;fa[x]=z; rs[y]=ls[x];fa[ls[x]]=y; ls[x]=y;fa[y]=x; MT(y);MT(x); } void Splay(int x) { int i,y,z; S[++top]=x; for(i=x;!Isroot(i);i=fa[i])S[++top]=fa[i]; while(top)PD(S[top--]); while(!Isroot(x)) { y=fa[x];z=fa[y]; if(!Isroot(y)) { if(y==ls[z])x==ls[y]?(Zig(y),Zig(x)):(Zag(x),Zig(x)); else x==rs[y]?(Zag(y),Zag(x)):(Zig(x),Zag(x)); } else x==ls[y]?Zig(x):Zag(x); } } void Access(int x) { for(int t=0;x;x=fa[x]) { Splay(x); rs[x]=t; MT(x);t=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); ls[y]=fa[x]=0; } int GF(int x) { if(F[x]!=x)F[x]=GF(F[x]); return F[x]; } void Kruscal() { int i=1,cnt=0,x,y,fx,fy; while(cnt<n-1) { if(edge[i].f){i++;continue;} x=GF(edge[i].x); y=GF(edge[i].y); if(x!=y) { F[x]=y; cnt++; Link(edge[i].id,edge[i].x); Link(edge[i].id,edge[i].y); } i++; } } int main() { int i,j,k,x,y,z;node tmp; scanf("%d%d%d",&n,&m,&q); for(i=1;i<=m;i++) { scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z); if(edge[i].y<edge[i].x)swap(edge[i].x,edge[i].y); edge[i].id=n+i;v[n+i]=edge[i].z; } sort(edge+1,edge+m+1,cmp2); for(i=1;i<=q;i++) { scanf("%d%d%d",&ty[i],&A[i],&B[i]); if(ty[i]==1)continue; if(A[i]>B[i])swap(A[i],B[i]); tmp.x=A[i];tmp.y=B[i]; j=lower_bound(edge+1,edge+m+1,tmp,cmp2)-edge; edge[j].f=1; } for(i=1;i<=m;i++)Hash[edge[i].id]=i; for(i=1;i<=n;i++)F[i]=i; sort(edge+1,edge+m+1,cmp1); Kruscal(); sort(edge+1,edge+m+1,cmp2); for(i=q;i>=1;i--) { if(ty[i]==1) { Makeroot(A[i]); Access(B[i]); Splay(B[i]); Ans[i]=Max[B[i]]; } else { tmp.x=A[i];tmp.y=B[i]; j=lower_bound(edge+1,edge+m+1,tmp,cmp2)-edge; Makeroot(A[i]); Access(B[i]); Splay(B[i]); if(edge[j].z<Max[B[i]]) { k=Hash[id[B[i]]]; Cut(edge[k].x,edge[k].id); Cut(edge[k].y,edge[k].id); Link(edge[j].x,edge[j].id); Link(edge[j].y,edge[j].id); } } } for(i=1;i<=q;i++)if(ty[i]==1)printf("%d\n",Ans[i]); }
相关文章推荐
- NKOJ 2991 (NOI 2014) 魔法森林 (动态树+最小生成树)
- NKOJ 2784 (APIO 2013) 道路费用(最小生成树+缩点)
- 最小生成树的纠结_交流电之王-ChinaUnix博客
- nkoj 3468 最小差值生成树 水题解
- MST - 最小生成树 (转 “笑着走完自己的路” 的博客) 写的不错
- NKOJ 2439 四叶草魔杖(最小生成树+状压dp/网络流)
- 51nod1640 【最小生成树】
- hdu 2122 (prime 最小生成树)
- ACM POJ 2421 Constructing Roads(简单最小生成树)
- POJ 2485 Highways 无向图最小生成树求最长的边
- Prim最小生成树算法(C++)
- 并查集 最小生成树(prime )
- 九度OJ 1144:Freckles(斑点) (最小生成树)
- POJ 3026 Borg Maze & UVA 10307 Killing Aliens in Borg Maze(BFS,最小生成树)
- 最小生成树之Kruskal算法(图论) By ACReaper
- 最小生成树之Kruskal算法
- HDU-4786 Fibonacci Tree(最小生成树[Kruskal])
- POJ 1789-Truck History 最小生成树 Kruskal算法
- hdu 3371(启发式合并的最小生成树)
- Slim Span POJ - 3522 最小生成树最大边和最小边之差最小