洛谷P1600 天天爱跑步
天天放毒...
首先介绍一个树上差分。
每次进入的时候记录贡献,跟出来的时候的差值就是子树贡献。
然后就可以做了。
发现考虑每个人的贡献有困难。
于是考虑每个观察员的答案。
把路径拆成两条,以lca分开。x -> z -> y,完全分成A,B两部分。
那么A:d[x] = w[z] + d[z];B:len - d[y] + N = w[z] - d[z] + N;
这里+ N是为了防止负数。
然后发现右边只跟z有关,这里的z可以是路径上任一点。
那么对于每个人,把需要树上差分统计的左边数值用vector记录。
然后跑一遍统计即可。
注意:如果lca能观测到这条路径,那么--,因为测了A,B两次。
看代码。
1 #include <cstdio> 2 #include <vector> 3 4 const int N = 300010; 5 6 inline void read(int &x) { 7 x = 0; 8 char c = getchar(); 9 while(c < '0' || c > '9') { 10 c = getchar(); 11 } 12 while(c >= '0' && c <= '9') { 13 x = (x << 3) + (x << 1) + c - 48; 14 c = getchar(); 15 } 16 return; 17 } 18 19 struct Edge { 20 int v, nex; 21 }edge[N << 1]; int top; 22 23 int n, m, e[N], w[N], binA[N << 1], binB[N << 1], cancel[N], d[N], fa[N][20], lm, ans[N]; 24 std::vector<int> vA[N], vB[N], vA_[N], vB_[N]; 25 26 inline void add(int x, int y) { 27 edge[++top].v = y; 28 edge[top].nex = e[x]; 29 e[x] = top; 30 return; 31 } 32 33 void DFS1(int x, int f) { 34 fa[x][0] = f; 35 d[x] = d[f] + 1; 36 for(int i = e[x]; i; i = edge[i].nex) { 37 int y = edge[i].v; 38 if(y != f) { 39 DFS1(y, x); 40 } 41 } 42 return; 43 } 44 45 inline void getlca() { 46 DFS1(1, 0); 47 while((1 << lm) < n) { 48 lm++; 49 } 50 for(int i = 1; i <= lm; i++) { 51 for(int x = 1; x <= n; x++) { 52 fa[x][i] = fa[fa[x][i - 1]][i - 1]; 53 } 54 } 55 return; 56 } 57 58 inline int lca(int x, int y) { 59 int t = lm; 60 while(d[x] > d[y]) { 61 std::swap(x, y); 62 } 63 while(t > -1 && d[y] > d[x]) { 64 if(d[fa[y][t]] >= d[x]) { 65 y = fa[y][t]; 66 } 67 t--; 68 } 69 if(x == y) { 70 return x; 71 } 72 t = lm; 73 while(t > -1 && fa[x][0] != fa[y][0]) { 74 if(fa[x][t] != fa[y][t]) { 75 x = fa[x][t]; 76 y = fa[y][t]; 77 } 78 t--; 79 } 80 return fa[x][0]; 81 } 82 83 void DFS(int x) { 84 int A = binA[w[x] + d[x]]; 85 int B = binB[w[x] - d[x] + N]; 86 for(int i = e[x]; i; i = edge[i].nex) { 87 int y = edge[i].v; 88 if(y != fa[x][0]) { 89 DFS(y); 90 } 91 } 92 for(int i = 0; i < vA[x].size(); i++) { 93 binA[vA[x][i]]++; 94 } 95 for(int i = 0; i < vB[x].size(); i++) { 96 binB[vB[x][i]]++; 97 } 98 ans[x] += binA[w[x] + d[x]] - A; 99 ans[x] += binB[w[x] - d[x] + N] - B; 100 for(int i = 0; i < vA_[x].size(); i++) { 101 binA[vA_[x][i]]--; 102 } 103 for(int i = 0; i < vB_[x].size(); i++) { 104 binB[vB_[x][i]]--; 105 } 106 return; 107 } 108 109 int main() { 110 read(n); 111 read(m); 112 int x, y, z; 113 for(int i = 1; i < n; i++) { 114 read(x); 115 read(y); 116 add(x, y); 117 add(y, x); 118 } 119 for(int i = 1; i <= n; i++) { 120 read(w[i]); 121 } 122 getlca(); 123 for(int i = 1; i <= m; i++) { 124 read(x); 125 read(y); 126 z = lca(x, y); 127 vA[x].push_back(d[x]); //d[x] = w[z] + d[z]; 128 vA_[z].push_back(d[x]); // 129 int len = d[x] + d[y] - 2 * d[z]; 130 vB[y].push_back(len - d[y] + N); //len - d[y] + N = w[z] - d[z] + N; 131 vB_[z].push_back(len - d[y] + N); 132 if(d[x] == w[z] + d[z]) { 133 cancel[z]++; 134 } 135 } 136 137 DFS(1); 138 139 for(int i = 1; i <= n; i++) { 140 printf("%d ", ans[i] - cancel[i]); 141 } 142 /*puts(""); 143 for(int i = 1; i < N * 2; i++) { 144 if(binB[i]) { 145 printf("binB[%d] = %d\n", i, binB[i]); 146 } 147 if(binA[i]) { 148 printf("binA[%d] = %d\n", i, binA[i]); 149 } 150 } 151 printf("over");*/ 152 153 return 0; 154 }
zbtrs大佬用主席树A了,还说显然是主席树,太强了%%%