bzoj2238

给出一个NN个点MM条边的无向带权图,以及QQ个询问,每次询问在图中删掉一条边后图的最小生成树。(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的边在下一条询问中依然存在)。

________________________________________

一个无向图,中有两种边,生成树上的边和其它边。

其它边删掉了,对最小生成树没有影响。

树上的边删掉了,如果上条边没有在环上,则不能再次生成树

在环上就可以再生成树。

首先生成树,不以树上的边就可以得到答案了。

枚举所有的边,如果边不在树上时,它可以和树上的某条链上的边构成环。

明显,链上的边的边长小于等于这条非树边的长度。

而树上的某一条边处在多环上时,如果删掉这个边,由于要构成最小生成树,那么肯定由最小非树边代替。

所以,每一条非树边对一条链上的所有边给一个权值,只要保留最小的(别的没有用),答案就是mst-当前边权值+保留的最小值

这个可以用树链剖分完成!

由于,每一树条边,只有覆盖它的最小非树边是用来“再生成最小生成树”的,其它的没有用。所以可以从小到大枚举非树边,它覆盖的边都标上这条非树边的权值(由于从小到大枚举,肯定最小)。

但是这样复杂度就变成了m*n.因为每次的链可能很长。

这时我们会发现,标边最小值的树边不会再用大的边标(只要最小的),所以可以用并查集再进行和并。

由于这样很条树边只会标记一次且路径压缩后不再一步步的向上跳,所以复杂度就成了n+m

!!!!!忘了一点,这个题很恶心,他共9个点,可是有4个点的数据不能生成树,也就是不连通!!!!!!

________________________________________

 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
",mxt);
92         else if(ans[no])printf("%d
",ans[no]);
93         else puts("Not connected");
94     }
95     return 0;
96 }
View Code
原文地址:https://www.cnblogs.com/gryzy/p/14686840.html