bzoj3631: [JLOI2014]松鼠的新家
阿新 • • 發佈:2018-11-06
col har ont 模板 參觀 開始 targe wap spa
bzoj3631
題目描述:松鼠的新家是一顆樹,新家有n個房間,由n - 1條邊連接。小熊維尼要來參觀,按一定的順序參觀n個房間,每到一個房間都要在那個房間拿走一個糖果(最後一個房間除外)。
問松鼠需要在每個房間各放幾個糖果。
輸入格式:第一行一個整數,表示房間的數量。
第二行n個整數,表示參觀的順序。
接下來n - 1行,每行兩個整數表示樹上相連的兩個房間。
輸入樣例:
5
1 4 5 3 2
1 2
2 4
2 3
4 5
輸出樣例:
1
2
1
2
1
解析:可以說是樹上差分的模板題,註意一下最後除了最開始參觀的房間,其他的房間的糖果數都要減1.
代碼如下:
1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 3e5 + 5; 7 int n, a[maxn], dep[maxn], fa[maxn][30], cnt[maxn]; 8 vector <int> ve[maxn];9 10 int read(void) { 11 char c; while (c = getchar(), c < ‘0‘ || c >‘9‘); int x = c - ‘0‘; 12 while (c = getchar(), c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘; return x; 13 } 14 15 void prepare(int u, int pre) { 16 dep[u] = dep[pre] + 1; 17 for (int i = 0; i < 29; ++ i) fa[u][i + 1] = fa[fa[u][i]][i]; 18 for (int i = 0; i < ve[u].size(); ++ i) { 19 int v = ve[u][i]; 20 if (v == pre) continue; 21 fa[v][0] = u; 22 prepare(v, u); 23 } 24 } 25 26 int getlca(int x, int y) { 27 if (x == 1 || y == 1) return 1; 28 if (dep[x] < dep[y]) swap(x, y); 29 for (int i = 29; i >= 0; -- i) 30 if (dep[fa[x][i]] >= dep[y]) { 31 x = fa[x][i]; 32 if (x == y) return x; 33 } 34 for (int i = 29; i >= 0; -- i) { 35 if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; 36 } 37 return fa[x][0]; 38 } 39 40 void dfs(int u, int pre) { 41 for (int i = 0; i < ve[u].size(); ++ i) { 42 int v = ve[u][i]; 43 if (v == pre) continue; 44 dfs(v, u); 45 cnt[u] += cnt[v]; 46 } 47 } 48 49 int main() { 50 n = read(); 51 for (int i = 1; i <= n; ++ i) a[i] = read(); 52 for (int i = 1; i < n; ++ i) { 53 int x = read(), y = read(); 54 ve[x].push_back(y); 55 ve[y].push_back(x); 56 } 57 prepare(1, 0); 58 for (int i = 1; i < n; ++ i) { //樹上差分 59 cnt[a[i]] ++; cnt[a[i + 1]] ++; 60 int lca = getlca(a[i], a[i + 1]); 61 cnt[lca] --; cnt[fa[lca][0]] --; 62 } 63 dfs(1, 0); 64 cnt[a[1]] ++; //第一個點+1,在後面-1,抵消 65 for (int i = 1; i <= n; ++ i) printf("%d\n", cnt[i] - 1); //每個點都-1 66 return 0; 67 }
bzoj3631: [JLOI2014]松鼠的新家