[POJ3417]Network

思路:
考虑加入新边对原图的影响:
  每加入一条边,相当于在原图中构成一个环,因此要使原图在这个环上断开,必须删去这条新边和环上任意一条树边。
统计每一条树边出现在多少个环中,计作$c$:
  1.$c=0$,则该边不属于任何一个环,因此删去这条边的同时删去任意一条新边即可,对答案的贡献是$m$;
  2.$c=1$,则该边仅属于一个环,因此删去这条边并删去该环上的新边即可,对答案的贡献是$1$;
  3.$cgeq 2$,则该边同时包含于多个环中,无论删去哪一个新边,总有别的环使原图连通,对答案的贡献是$0$。
因此我们可以统计$c$来得到答案。
我们可以利用树上差分的思想,对于每条新边$(u,v)$,$f_u=f_u+1$,$f_v=f_v+1$,$f_{LCA(u,v)}=f_{LCA(u,v)}+1$。
最后用树形DP求出每条边被环包含的次数。
Tarjan求LCA。
但是在OJ上测会TLE,必须要把vector改成前向星才可以。

 1 #include<cstdio>
 2 #include<cctype>
 3 inline int getint() {
 4     char ch;
 5     while(!isdigit(ch=getchar()));
 6     int x=ch^'0';
 7     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 8     return x;
 9 }
10 const int root=1,nil=0;
11 const int V=100001;
12 struct Edge {
13     int to,next;
14 };
15 int sz=0;
16 Edge edge[V<<2];
17 int e[V]={0},q[V]={0};
18 inline void add_edge(const int u,const int v) {
19     edge[++sz]=(Edge){v,e[u]};
20     e[u]=sz;
21 }
22 inline void add_query(const int u,const int v) {
23     edge[++sz]=(Edge){v,q[u]};
24     q[u]=sz;
25 }
26 class DisjointSet {
27     private:
28         int anc[V];
29     public:
30         DisjointSet() {
31             for(int i=0;i<V;i++) anc[i]=i;
32         }
33         int Find(const int x) {
34             return x==anc[x]?x:anc[x]=Find(anc[x]);
35         }
36         void Union(const int x,const int y) {
37             anc[Find(x)]=Find(y);
38         }
39 };
40 DisjointSet s;
41 bool vis[V]={0};
42 int f[V]={0};
43 void Tarjan(const int x,const int par) {
44     for(int i=e[x];i;i=edge[i].next) {
45         int &y=edge[i].to;
46         if(y!=par) Tarjan(y,x);
47     }
48     for(int i=q[x];i;i=edge[i].next) {
49         int &y=edge[i].to;
50         if(!vis[y]) continue;
51         int lca=s.Find(y);
52         f[x]++,f[y]++,f[lca]-=2;
53     }
54     s.Union(x,par);
55     vis[x]=true;
56 }
57 int cnt[2]={-1};
58 void DP(const int x,const int par) {
59     for(int i=e[x];i;i=edge[i].next) {
60         int &y=edge[i].to;
61         if(y==par) continue;
62         DP(y,x);
63         f[x]+=f[y];
64     }
65     if(f[x]<2) cnt[f[x]]++;
66 }
67 int main() {
68     int n=getint(),m=getint();
69     for(int i=1;i<n;i++) {
70         int u=getint(),v=getint();
71         add_edge(u,v);
72         add_edge(v,u);
73     }
74     for(int i=1;i<=m;i++) {
75         int u=getint(),v=getint();
76         add_query(u,v);
77         add_query(v,u);
78     }
79     Tarjan(root,nil);
80     DP(root,nil);
81     printf("%d
",cnt[0]*m+cnt[1]);
82     return 0;
83 }
原文地址:https://www.cnblogs.com/skylee03/p/7435044.html