BZOJ_2238_Mst_树剖+线段树
BZOJ_2238_Mst_树剖+线段树
Description
给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树。(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的边在下一条询问中依然存在)
Input
第一行两个正整数N,M(N<=50000,M<=100000)表示原图的顶点数和边数。
下面M行,每行三个整数X,Y,W描述了图的一条边(X,Y),其边权为W(W<=10000)。保证两点之间至多只有一条边。
接着一行一个正整数Q,表示询问数。(1<=Q<=100000)
下面Q行,每行一个询问,询问中包含一个正整数T,表示把编号为T的边删掉(边从1到M按输入顺序编号)。
Output
Q行,对于每个询问输出对应最小生成树的边权和的值,如果图不连通则输出“Not connected”
Sample Input
4 4
1 2 3
1 3 5
2 3 9
2 4 1
4
1
2
3
4
1 2 3
1 3 5
2 3 9
2 4 1
4
1
2
3
4
Sample Output
15
13
9
Not connected
我们先求任意一棵最小生成树。
如果被删除的边(x->y)不在树上,则直接输出最小生成树的边权和即可。
否则我们要找到所有能使x,y两点连通的边中边权最小的那个,把它换上。
在插入每条非树边时用这条边的权值更新树上x->y路径上权值的最小值,同时记录边权最小的边的编号。
然后这个可以用树剖+线段树维护出来。
注意如果图不联通要输出Not connected,
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define ls p<<1 #define rs p<<1|1 #define N 100050 int head[N],to[N<<1],nxt[N<<1],cnt,n,m; int mn[N<<2],f[N],sum,ref[N],val[N<<1]; int dep[N],fa[N],top[N],siz[N],son[N],idx[N],tot; struct A { int x,y,z,flg,id; }a[N]; bool cmp1(const A &x,const A &y) {return x.z<y.z;} bool cmp2(const A &x,const A &y) {return x.id<y.id;} int find(int x) { return f[x]==x?x:f[x]=find(f[x]); } inline void add(int u,int v,int w) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w; } void dfs1(int x,int y) { int i; dep[x]=dep[y]+1; fa[x]=y; siz[x]=1; for(i=head[x];i;i=nxt[i]) { if(to[i]!=y) { ref[val[i]]=to[i]; dfs1(to[i],x); siz[x]+=siz[to[i]]; if(siz[to[i]]>siz[son[x]]) son[x]=to[i]; } } } void dfs2(int x,int t) { top[x]=t;idx[x]=++tot; if(son[x]) dfs2(son[x],t); int i; for(i=head[x];i;i=nxt[i]) { if(to[i]!=fa[x]&&to[i]!=son[x]) { dfs2(to[i],to[i]); } } } void update(int l,int r,int x,int y,int v,int p) { if(x<=l&&y>=r) { mn[p]=min(mn[p],v); return ; } int mid=(l+r)>>1; if(x<=mid) update(l,mid,x,y,v,ls); if(y>mid) update(mid+1,r,x,y,v,rs); } int query(int l,int r,int x,int p) { if(l==r) return mn[p]; int mid=(l+r)>>1; if(x<=mid) return min(mn[p],query(l,mid,x,ls)); else return min(mn[p],query(mid+1,r,x,rs)); } int main() { scanf("%d%d",&n,&m); int i,ne=0,x,y; for(i=1;i<=n;i++) f[i]=i; for(i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z),a[i].id=i; sort(a+1,a+m+1,cmp1); for(i=1;i<=m;i++) { int dx=find(a[i].x),dy=find(a[i].y); if(dx!=dy) { add(a[i].x,a[i].y,a[i].id); add(a[i].y,a[i].x,a[i].id); ne++; f[dx]=dy; a[i].flg=1; sum+=a[i].z; if(ne==n-1) break; } } int q; if(ne<n-1) { scanf("%d",&q); while(q--) { puts("Not connected"); } return 0; } dfs1(1,0); dfs2(1,1); for(i=1;i<=4*n;i++) mn[i]=1<<30; sort(a+1,a+m+1,cmp2); for(i=1;i<=m;i++) { if(!a[i].flg) { x=a[i].x,y=a[i].y; while(top[x]!=top[y]) { if(dep[top[x]]>dep[top[y]]) swap(x,y); update(1,n,idx[top[y]],idx[y],a[i].z,1); y=fa[top[y]]; } if(dep[x]<dep[y]) swap(x,y); if(x!=y)update(1,n,idx[y]+1,idx[x],a[i].z,1); } } int k; scanf("%d",&q); while(q--) { scanf("%d",&k); if(!a[k].flg) { printf("%d\n",sum); }else { x=a[k].x;y=a[k].y; int re=query(1,n,idx[ref[k]],1); if(re==(1<<30)) { puts("Not connected"); }else { printf("%d\n",sum-a[k].z+re); } } } }