bzoj2238
给出一个NN个点MM条边的无向带权图,以及QQ个询问,每次询问在图中删掉一条边后图的最小生成树。(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的边在下一条询问中依然存在)。
________________________________________
一个无向图,中有两种边,生成树上的边和其它边。
其它边删掉了,对最小生成树没有影响。
树上的边删掉了,如果上条边没有在环上,则不能再次生成树
在环上就可以再生成树。
首先生成树,不以树上的边就可以得到答案了。
枚举所有的边,如果边不在树上时,它可以和树上的某条链上的边构成环。
明显,链上的边的边长小于等于这条非树边的长度。
而树上的某一条边处在多环上时,如果删掉这个边,由于要构成最小生成树,那么肯定由最小非树边代替。
所以,每一条非树边对一条链上的所有边给一个权值,只要保留最小的(别的没有用),答案就是mst-当前边权值+保留的最小值
这个可以用树链剖分完成!
由于,每一树条边,只有覆盖它的最小非树边是用来“再生成最小生成树”的,其它的没有用。所以可以从小到大枚举非树边,它覆盖的边都标上这条非树边的权值(由于从小到大枚举,肯定最小)。
但是这样复杂度就变成了m*n.因为每次的链可能很长。
这时我们会发现,标边最小值的树边不会再用大的边标(只要最小的),所以可以用并查集再进行和并。
由于这样很条树边只会标记一次且路径压缩后不再一步步的向上跳,所以复杂度就成了n+m
!!!!!忘了一点,这个题很恶心,他共9个点,可是有4个点的数据不能生成树,也就是不连通!!!!!!
________________________________________
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 int n,m,q; 5 struct edge 6 { 7 int u,v,w,no,nxt; 8 }e[maxn<<1],ee[maxn]; 9 int head[maxn],js; 10 void addage(int u,int v,int w,int no) 11 { 12 e[++js].u=u;e[js].v=v;e[js].w=w;e[js].no=no; 13 e[js].nxt=head[u];head[u]=js; 14 } 15 bool cmp(edge a,edge b) 16 { 17 return a.w<b.w; 18 } 19 int f[maxn],ff[maxn]; 20 int find(int *f,int x) 21 { 22 if(f[x]==x)return x; 23 else return f[x]=find(f,f[x]); 24 } 25 int ans[maxn],fa[maxn],dep[maxn],mxt,upno[maxn]; 26 bool intr[maxn]; 27 void dfs(int u,int fat) 28 { 29 fa[u]=fat;ff[u]=u;dep[u]=dep[fat]+1; 30 for(int i=head[u];i;i=e[i].nxt) 31 { 32 int v=e[i].v; 33 if(v==fat)continue; 34 upno[v]=e[i].no; 35 dfs(v,u); 36 } 37 } 38 int main() 39 { 40 scanf("%d%d",&n,&m); 41 for(int u,v,w,i=1;i<=m;++i) 42 { 43 scanf("%d%d%d",&ee[i].u,&ee[i].v,&ee[i].w); 44 ee[i].no=i; 45 } 46 sort(ee+1,ee+1+m,cmp); 47 for(int i=1;i<=n;++i)f[i]=i; 48 int tj=0; 49 for(int i=1;i<=m;++i) 50 { 51 int u=ee[i].u,v=ee[i].v; 52 if(find(f,u)!=find(f,v)) 53 { 54 addage(u,v,ee[i].w,ee[i].no); 55 addage(v,u,ee[i].w,ee[i].no); 56 mxt+=ee[i].w; 57 intr[ee[i].no]=1; 58 u=find(f,u),v=find(f,v); 59 f[u]=v; 60 tj++; 61 if(tj==n-1)break; 62 } 63 } 64 dfs(1,0); 65 for(int i=1;i<=m;++i) 66 { 67 int no=ee[i].no; 68 if(intr[no]==0) 69 { 70 ans[no]=mxt; 71 int u=ee[i].u,v=ee[i].v; 72 u=find(ff,u);v=find(ff,v); 73 while(u!=v) 74 { 75 if(dep[v]>dep[u])swap(u,v); 76 ans[upno[u]]=ee[i].w; 77 ff[u]=fa[u];u=find(ff,u); 78 } 79 } 80 } 81 for(int i=1;i<=m;++i)if(ans[ee[i].no])ans[ee[i].no]+=mxt-ee[i].w; 82 scanf("%d",&q); 83 for(int no,i=1;i<=q;++i) 84 { 85 scanf("%d",&no); 86 if(tj!=n-1) 87 { 88 puts("Not connected"); 89 continue; 90 } 91 if(intr[no]==0)printf("%d\n",mxt); 92 else if(ans[no])printf("%d\n",ans[no]); 93 else puts("Not connected"); 94 } 95 return 0; 96 }