Descriptionnode
Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has just received a bad news which denotes that DxtNetwork(DN), the SN's business rival, intents to attack the network of SN. More unfortunately, the original network of SN is so weak that we can just treat it as a tree. Formally, there are N nodes in SN's network, N-1 bidirectional channels to connect the nodes, and there always exists a route from any node to another. In order to protect the network from the attack, Yixght builds _M_new bidirectional channels between some of the nodes.ios
As the DN's best hacker, you can exactly destory two channels, one in the original network and the other among the M new channels. Now your higher-up wants to know how many ways you can divide the network of SN into at least two parts.ide
Inputui
The first line of the input file contains two integers: N (1 ≤ N ≤ 100 000), M (1 ≤ M ≤ 100 000) — the number of the nodes and the number of the new channels.spa
Following N-1 lines represent the channels in the original network of SN, each pair (a,b) denote that there is a channel between node a and node b.code
Following M lines represent the new channels in the network, each pair (a,b) denote that a new channel between node a and node b is added to the network of SN.orm
Outputip
Output a single integer — the number of ways to divide the network into at least two parts.get
Sample Inputinput
4 1
1 2
2 3
1 4
3 4
Sample Output
3
樹上亂搞題
最開始看了沒有思路,次日再看仍是沒有思路GG... 本身想到的是統計本身子樹中有多少條附加邊的一端,可是沒細想,感受狀況不少,很差討論。
事實上咱們考慮,每多加一條非樹邊,在不重的狀況下,樹上都會多出一個環。
考慮斷掉某條樹邊:
1.它可能沒進入環,這時很顯然再隨意斷開一條非樹邊便可。對答案的貢獻爲m。
2.它進入了一個環,這時咱們再斷開環中的那條非樹邊,成爲一種方案。
3.它進入了兩個環,樹上部分紅爲兩部分,但由於這條邊處於兩個環中,因此還有兩條非樹邊從上半部分連到下半部分,沒法使圖成爲兩塊。
4.它進入了多條環時與進入了兩個環時狀況相似,沒法使圖成爲兩塊。
那這時思路就很顯然了,對於每條非樹邊,咱們把環上的每條樹邊入環個數++,可是咱們發現這樣作的話時間複雜度比較高,由於這樣作須要遍歷路徑上的每一條邊。這時考慮能不能把邊轉移到點上來記錄,巨佬這時很容易想到運用樹上差分的思想來解決(我仍是太菜了,徹底沒想到)。對於每條非樹邊\((u,v)\):
a[u]++;a[v]++;a[lca(u,v)]-=2;
最後對於每一個點按照上面的方法處理便可。
注意:不須要考慮根節點
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> using namespace std; int read() { int x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*w; } const int N=100010; int n,m,x,y,cnt,ans; int head[N],deep[N],f[N][20],a[N]; struct node{ int to,next; }edge[2*N]; void add(int x,int y) { cnt++; edge[cnt].to=y; edge[cnt].next=head[x]; head[x]=cnt; } void init() { for(int i=1;i<=19;i++) for(int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1]; } void dfs(int k,int fa) { for(int i=head[k];i;i=edge[i].next) { int v=edge[i].to; if(v==fa) continue; deep[v]=deep[k]+1;f[v][0]=k; dfs(v,k); } } int LCA(int x,int y) { if(deep[x]<deep[y]) swap(x,y); for(int i=19;i>=0;i--) { if(deep[f[x][i]]>=deep[y]) x=f[x][i]; } if(x==y) return x; for(int i=19;i>=0;i--) { if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; } return f[x][0]; } void get(int k,int fa) { for(int i=head[k];i;i=edge[i].next) { int v=edge[i].to; if(v==fa) continue; get(v,k); a[k]+=a[v]; } } int main() { n=read();m=read(); for(int i=1;i<n;i++) { x=read();y=read(); add(x,y);add(y,x); } dfs(1,0);init(); for(int i=1;i<=m;i++) { x=read();y=read(); int lca=LCA(x,y); a[x]++;a[y]++;a[lca]-=2; } get(1,0); for(int i=2;i<=n;i++) { if(a[i]==0) ans+=m; else if(a[i]==1) ans++; } cout<<ans; }