原题来自:POJ 3417
Dark 是一张无向图,图中有 N 个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark 有 N–1 条主要边,并且 Dark 的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark 还有 M 条附加边。
你的任务是把 Dark 斩为不连通的两部分。一开始 Dark 的附加边都处于无敌状态,你只能选择一条主要边切断。一旦你切断了一条主要边,Dark 就会进入防御模式,主要边会变为无敌的而附加边可以被切断。但是你的能力只能再切断 Dark 的一条附加边。
现在你想要知道,一共有多少种方案可以击败 Dark。注意,就算你第一步切断主要边之后就已经把 Dark 斩为两截,你也需要切断一条附加边才算击败了 Dark。
第一行包含两个整数 N 和 M;
之后 N – 1 行,每行包括两个整数 A 和 B,表示 A 和 B 之间有一条主要边;
之后 M 行以同样的格式给出附加边。
输出一个整数表示答案。
4 1
1 2
2 3
1 4
3 4
3
对于 20% 的数据,1≤N,M≤100;
对于 100% 的数据,1≤N≤10^5,1≤M≤2×10^5。数据保证答案不超过 2^31?1。
_______________________________________________________________________________________
每一条非树边,都对应这一条树上的链,那么砍断这条非数遍后对应链上的数遍砍断就可以把图分成两半。
但是两条非树边对应的链可能有重合,这样砍断重合的边,图就不能分成两半。
所以对于每条非树边,要统计对应的树链上的各个边的重叠次数。这就用到了树上查分。
所以,树边的重叠次数为1是,答案加一,表示砍断树边后有一条非树边与之对应,可以破开环,使图成为两半。
如果重叠次数为2及以上,说明砍断该树边,还有两条及以上的非树边相连,不能把图分成两半,答案不变。
如果重叠次数为0,说明该树边不在环上,切断它直接可以把图分成两半,所以非树边可以任意选,答案加M.
_______________________________________________________________________________________
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 int n,m; 5 struct edge 6 { 7 int u,v,nxt; 8 }e[maxn<<1]; 9 int head[maxn],js; 10 int dep[maxn],val[maxn]; 11 int f[maxn][20]; 12 long long ans; 13 void addage(int u,int v) 14 { 15 e[++js].u=u;e[js].v=v; 16 e[js].nxt=head[u];head[u]=js; 17 } 18 void dfs(int u,int fa) 19 { 20 dep[u]=dep[fa]+1; 21 f[u][0]=fa; 22 for(int i=1;i<20;++i)f[u][i]=f[f[u][i-1]][i-1]; 23 for(int i=head[u];i;i=e[i].nxt) 24 { 25 int v=e[i].v; 26 if(fa!=v)dfs(v,u); 27 } 28 } 29 int lca(int u,int v) 30 { 31 if(dep[u]<dep[v])swap(u,v); 32 for(int i=19;i>=0;--i)if(dep[f[u][i]]>=dep[v])u=f[u][i]; 33 if(u==v)return u; 34 for(int i=19;i>=0;--i)if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i]; 35 return f[u][0]; 36 } 37 void dfsf(int u,int fa) 38 { 39 for(int i=head[u];i;i=e[i].nxt) 40 { 41 int v=e[i].v; 42 if(v!=fa) 43 { 44 dfsf(v,u); 45 val[u]+=val[v]; 46 } 47 } 48 if(val[u]==0 && u!=1)ans+=m; 49 else if(val[u]==1)ans++; 50 } 51 int main() 52 { 53 scanf("%d%d",&n,&m); 54 for(int u,v,i=1;i<n;++i) 55 { 56 scanf("%d%d",&u,&v); 57 addage(u,v);addage(v,u); 58 } 59 dfs(1,0); 60 for(int u,v,i=0;i<m;++i) 61 { 62 scanf("%d%d",&u,&v); 63 int l=lca(u,v); 64 ++val[u];++val[v]; 65 val[l]-=2; 66 } 67 dfsf(1,0); 68 cout<<ans; 69 return 0; 70 }
原文:https://www.cnblogs.com/gryzy/p/10355520.html