一本通1553【例 2】暗的连锁
1553:【例 2】暗的连锁
时间限制: 1000 ms 内存限制: 524288 KB
题目描述
原题来自: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。
sol:在一棵树上去掉一条边后一定会不连通,但是还有m条附加边,就用差分记录一条路径(或边)上覆盖了几条附加边,0:ans+=m ; 1:ans++; >1: cnotinue
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; const int N=100005,M=200005; int n,m; struct Tree { int tot,Next[M],to[M],head[N]; inline void add(int x,int y) { Next[++tot]=head[x]; to[tot]=y; head[x]=tot; return; } int F[N][23],Depth[N]; inline void dfs(int x,int fa) { int i; F[x][0]=fa; Depth[x]=Depth[fa]+1; for(i=head[x];i;i=Next[i]) if(to[i]!=fa) { dfs(to[i],x); } return; } inline void Pre() { int i,j; dfs(1,1); // for(i=1;i<=n;i++) // { // printf("fa[%d]=%d\n",i,F[i][0]); // } // exit(0); for(i=1;i<=19;i++) { for(j=1;j<=n;j++) F[j][i]=F[F[j][i-1]][i-1]; } return; } inline int Ask_Lca(int x,int y) { int i; if(Depth[x]<Depth[y]) swap(x,y); for(i=19;~i;i--) if(Depth[F[x][i]]>=Depth[y]) { x=F[x][i]; } if(x==y) return x; for(i=19;~i;i--) if(F[x][i]!=F[y][i]) { x=F[x][i]; y=F[y][i]; } return F[x][0]; } int Chafen[N]; inline void Ins(int x,int y) { Chafen[x]++; Chafen[y]++; Chafen[Ask_Lca(x,y)]-=2; return; } inline void Dfs(int x) { // printf("x=%d\n",x); int i; for(i=head[x];i;i=Next[i]) if(to[i]!=F[x][0]) { Dfs(to[i]); Chafen[x]+=Chafen[to[i]]; } return; } }T; int main() { // freopen("yam0.in","r",stdin); int i,x,y; scanf("%d%d",&n,&m); for(i=1;i<n;i++) { scanf("%d%d",&x,&y); T.add(x,y); T.add(y,x); } T.Pre(); for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); T.Ins(x,y); } T.Dfs(1); int ans=0; for(i=2;i<=n;i++) { switch (T.Chafen[i]) { case 0: ans+=m; break; case 1: ans++; break; default: break; } } printf("%d\n",ans); return 0; } /* input 4 1 1 2 2 3 1 4 3 4 output 3 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!