題目
題目描述
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<=105,1 <= M <= 2*105。數據保證答案不超過 231 - 1。
分析
一本通(提高篇)P250
每一條附加邊(u,v)都相當於把樹上(u,v)路徑上的所有邊都“覆蓋”了一遍,斷其中一條邊不會斷樹
統計出每一條邊“覆蓋”了幾次,0次的直接斷掉就會斷樹,任意斷一條附加邊即可,1次的斷附加邊的方案唯一,2次及以上無解
統計覆蓋次數用到了樹上差分,把邊權下放到下面的點
差分學習資料:差分數組 and 樹上差分 By 顧z
代碼

1 /********************** 2 User:Mandy.H.Y 3 Language:c++ 4 Problem: 5 Algorithm: 6 Date: 7 **********************/ 8 9 //LCA,樹上差分 10 11 #include<bits/stdc++.h> 12 #define Max(x,y) ((x) > (y) ? (x) : (y)) 13 #define Min(x,y) ((x) < (y) ? (x) : (y)) 14 15 using namespace std; 16 17 const int maxn = 1e5 + 5; 18 const int maxm = 2e5 + 5; 19 20 int n,m,ans; 21 int size,first[maxn],score[maxn]; 22 int top[maxn],cnt[maxn],father[maxn],dep[maxn]; 23 24 struct Edge{ 25 int v,nt; 26 }edge[maxm]; 27 28 char *TT,*mo,but[(1 << 15) + 2]; 29 #define getchar() ((TT == mo && (mo = ((TT = but) + fread(but,1,1 << 15,stdin)),TT == mo)) ? -1 : *TT++) 30 template<class T>inline void read(T &x){ 31 x = 0;bool flag = 0;char ch = getchar(); 32 while( ! isdigit(ch)) flag |= ch == '-',ch = getchar(); 33 while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar(); 34 if(flag) x = -x; 35 } 36 37 template<class T>inline void putch(const T x){ 38 if(x > 9) putch(x / 10); 39 putchar(x % 10 | 48); 40 } 41 42 template<class T>inline void put(const T x){ 43 if(x < 0) putchar('-'),putch(-x); 44 else putch(x); 45 } 46 47 void file(){ 48 freopen("yam2.in","r",stdin); 49 // freopen("network.out","w",stdout); 50 } 51 52 void eadd(int u,int v){ 53 edge[++ size].v = v; 54 edge[size].nt = first[u]; 55 first[u] = size; 56 } 57 58 void readdata(){ 59 read(n);read(m); 60 for(int i = 1;i < n; ++ i){ 61 int u,v; 62 read(u);read(v); 63 eadd(u,v);eadd(v,u); 64 } 65 } 66 67 void dfs(int u,int f,int d){ 68 top[u] = u;dep[u] = d; 69 int mcnt = 0,son = 0; 70 father[u] = f;cnt[u] = 1; 71 72 for(int i = first[u];i;i = edge[i].nt){ 73 int v = edge[i].v; 74 if(v == f) continue; 75 dfs(v,u,d + 1); 76 cnt[u] += cnt[v]; 77 if(mcnt < cnt[v]){ 78 mcnt = cnt[v]; 79 son = v; 80 } 81 } 82 83 if(son) top[son] = u; 84 } 85 86 int find(int u){ 87 return top[u] == u ? u : top[u] = find(top[u]); 88 } 89 90 int LCA(int x,int y){ 91 if(find(x) == find(y)) return dep[x] < dep[y] ? x : y; 92 else return dep[top[x]] <dep[top[y]] ? LCA(x,father[top[y]]) : LCA(y,father[top[x]]); 93 //沒想到有一天模板也會打錯 94 } 95 96 void dfs1(int u){ 97 for(int i = first[u];i;i = edge[i].nt){ 98 int v = edge[i].v; 99 100 if(v == father[u]) continue; 101 102 dfs1(v); 103 score[u] += score[v]; //累加 104 if(score[v] == 0){ 105 ans+=m; 106 } else if(score[v] == 1) ans++; 107 } 108 } 109 110 void work(){ 111 112 dfs(1,0,0); 113 114 for(int i = 1;i <= m; ++ i){ 115 int u,v; 116 read(u);read(v); 117 int anc = LCA(u,v); 118 score[u]++,score[v]++; 119 score[anc]-=2; 120 //差分 121 //把邊下放到點 122 } 123 124 dfs1(1); 125 // put(score[1]);puts(""); 126 put(ans); 127 } 128 129 int main(){ 130 // file(); 131 readdata(); 132 work(); 133 return 0; 134 }