LOJ10131暗的连锁

题目描述

原题来自: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% 的数据,1N,M100;

对于 100% 的数据,1N10^5,1M2×10^5。数据保证答案不超过 2^311。

_______________________________________________________________________________________

每一条非树边,都对应这一条树上的链,那么砍断这条非数遍后对应链上的数遍砍断就可以把图分成两半。

但是两条非树边对应的链可能有重合,这样砍断重合的边,图就不能分成两半。

所以对于每条非树边,要统计对应的树链上的各个边的重叠次数。这就用到了树上查分。

所以,树边的重叠次数为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 }
View Code

 

猜你喜欢

转载自www.cnblogs.com/gryzy/p/10355520.html