洛谷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 }
AC代码

zbtrs大佬用主席树A了,还说显然是主席树,太强了%%%

 

posted @ 2018-09-17 21:56  huyufeifei  阅读(146)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜