POJ 3471 Network

http://acm.ocrosoft.com/problem.php?cid=2184&pid=0

给定一颗最小生成树,然后再给m条的新边,求删去一条树边和新边后有多少种办法使图分成独立的两个连通块。

每给定一条新边,必定会出现一个环。

假定对于某点,只有一条树边,断开这一条树边,则

1、对于该点,若没有新边,即不存在环,任意的,可以删去图中的任意一条新边,方法数+m;

2、对于该点,若只有一条新边,即只存在一个环,可以删去这一条新边,方法数+1;

若对于某点,边数(新边+树边)大于等于三,即经过该点有两个以上环,则不能通过断去两条边的方式获得两个独立的连通块。

当添加一条新边 u,v 会形成一个环,那么环上各点经过环的数量都加一,所以需要多次修改。

采用边差分的方式记录并不断修改经过该点的环的数量 ,此时需要LCA来帮助确定差分作用的区间。

在新边读入完成后,还原差分得到最后的图,按上述方式计算得到方法数。

 1 #include<cstdio>
 2 #include<cmath> 
 3 #include<iostream> 
 4 #include<cstring> 
 5 #include<algorithm>
 6 #include<stack>
 7 #include<queue>
 8 #include<map>
 9 #include<vector>
10 #include<set>
11 #include<iomanip>
12 #define inf 0x3f3f3f3f
13 #define ll long long
14 #define debug printf("yes\n");
15 using namespace std; 
16 int n,m,tot,x,y,p,ans,lg[100010],diff[100010<<1],dep[100010],to[100010<<2],nxt[100010<<2],head[100010<<2],fa[100010][20];
17 int read(){
18     int x=0,f=1;char ch=getchar();
19     while(ch<'0'||ch>'9'){
20         if(ch=='-')f=-1;
21         ch=getchar();
22     }
23     while(ch>='0'&&ch<='9'){
24         x=x*10+ch-'0';
25         ch=getchar();
26     }
27     return x*f;
28 }
29 void add(int x,int y){
30     to[++tot]=y;
31     nxt[tot]=head[x];
32     head[x]=tot;
33 }
34 void dfs_lca(int x,int father){
35     fa[x][0]=father;dep[x]=dep[father]+1;
36     for(int i=1;i<=lg[dep[x]];++i)
37         fa[x][i]=fa[fa[x][i-1]][i-1];//状态转移计算出各种2^i跳法到达的位置 
38     for(int i=head[x];i;i=nxt[i])
39         if(to[i]!=father)dfs_lca(to[i],x);
40 }
41 int lca(int x,int y){
42     if(dep[x]<dep[y]) swap(x,y);
43     while(dep[x]>dep[y])
44         x=fa[x][lg[dep[x]-dep[y]]-1];
45     if(x==y)    return x;
46     for(int k=lg[dep[x]]-1;k>=0;--k)
47         if(fa[x][k]!=fa[y][k])
48             x=fa[x][k],y=fa[y][k];
49     return fa[x][0];
50 }
51 void dfs_cf(int u,int father){
52     for(int i=head[u];i;i=nxt[i]){
53         if(to[i]==father)    continue;
54         dfs_cf(to[i],u);
55         diff[u]+=diff[to[i]];
56     }
57 }
58 int main(){
59     n=read();m=read();
60     for(int i=1;i<=n;++i)
61         lg[i]=lg[i-1]+(1<<lg[i-1]==i);    //预处理各深度log2 
62     for(int i=1;i<n;++i){
63         x=read();y=read();
64         add(x,y);add(y,x);//构建最小树的边 
65     }
66     dfs_lca(1,0);
67     for(int i=1;i<=m;++i){
68         x=read();y=read();
69         p=lca(x,y);
70         ++diff[x];++diff[y];diff[p]-=2;    //边差分,记录环
71     }
72     dfs_cf(1,0);//还原为经过该点的环的数量 
73     for(int i=2;i<=n;++i)
74         if(diff[i]==0)    ans+=m;
75         else if(diff[i]==1)    ans++;
76     printf("%d",ans);
77     return 0;
78 }

猜你喜欢

转载自www.cnblogs.com/PdrEam/p/12942180.html