洛谷P4242 树上的毒瘤

解:首先有个套路是一条边的权值是[两端点颜色不同]。这个用树剖直接维护,支持修改。

每次询问建虚树,查询虚树上每条边的权值。然后树形DP,用开店的方法,每个点链加链查。

 

  1 #include <bits/stdc++.h>
  2 
  3 #define forson(x, i) for(int i = e[x]; i; i = edge[i].nex)
  4 
  5 typedef long long LL;
  6 const int N = 100010;
  7 
  8 struct Edge {
  9     int nex, v;
 10     LL len;
 11 }edge[N << 1], EDGE[N]; int tp, TP;
 12 
 13 int e[N], top[N], fa[N], son[N], siz[N], d[N], pos[N], id[N], num, val[N], n, imp2[N];
 14 int sum[N << 2], lc[N << 2], rc[N << 2], tag[N << 2];
 15 int imp[N], K, stk[N], Top, RT, Time, E[N], vis[N], use[N], DEEP[N];
 16 LL SIZ[N], ans[N], D[N];
 17 
 18 inline void add(int x, int y) {
 19     tp++;
 20     edge[tp].v = y;
 21     edge[tp].nex = e[x];
 22     e[x] = tp;
 23     return;
 24 }
 25 
 26 /// ------------------- tree 1 -------------------------
 27 
 28 void DFS_1(int x, int f) { /// get fa son siz d
 29     fa[x] = f;
 30     siz[x] = 1;
 31     d[x] = d[f] + 1;
 32     forson(x, i) {
 33         int y = edge[i].v;
 34         if(y == f) continue;
 35         DFS_1(y, x);
 36         siz[x] += siz[y];
 37         if(siz[y] > siz[son[x]]) {
 38             son[x] = y;
 39         }
 40     }
 41     return;
 42 }
 43 
 44 void DFS_2(int x, int f) { /// get top pos id
 45     top[x] = f;
 46     pos[x] = ++num;
 47     id[num] = x;
 48     if(son[x]) DFS_2(son[x], f);
 49     forson(x, i) {
 50         int y = edge[i].v;
 51         if(y == fa[x] || y == son[x]) continue;
 52         DFS_2(y, y);
 53     }
 54     return;
 55 }
 56 
 57 /// ------------------ seg 1 ----------------------
 58 
 59 #define ls (o << 1)
 60 #define rs (o << 1 | 1)
 61 
 62 inline void pushup(int o) {
 63     lc[o] = lc[ls];
 64     rc[o] = rc[rs];
 65     sum[o] = sum[ls] + sum[rs] + (rc[ls] != lc[rs]);
 66     return;
 67 }
 68 
 69 inline void pushdown(int o) {
 70     if(tag[o] != -1) {
 71         lc[ls] = rc[ls] = tag[ls] = tag[o];
 72         lc[rs] = rc[rs] = tag[rs] = tag[o];
 73         sum[ls] = sum[rs] = 0;
 74         tag[o] = -1;
 75     }
 76     return;
 77 }
 78 
 79 #undef ls
 80 #undef rs
 81 
 82 void build(int l, int r, int o) {
 83     if(l == r) {
 84         lc[o] = rc[o] = val[id[r]];
 85         sum[o] = 0;
 86         return;
 87     }
 88     int mid = (l + r) >> 1;
 89     build(l, mid, o << 1);
 90     build(mid + 1, r, o << 1 | 1);
 91     pushup(o);
 92     return;
 93 }
 94 
 95 void change(int L, int R, int v, int l, int r, int o) {
 96     if(L <= l && r <= R) {
 97         lc[o] = rc[o] = tag[o] = v;
 98         sum[o] = 0;
 99         return;
100     }
101     int mid = (l + r) >> 1;
102     pushdown(o);
103     if(L <= mid) change(L, R, v, l, mid, o << 1);
104     if(mid < R) change(L, R, v, mid + 1, r, o << 1 | 1);
105     pushup(o);
106     return;
107 }
108 
109 int ask(int p, int l, int r, int o) {
110     if(l == r) return lc[o];
111     int mid = (l + r) >> 1;
112     pushdown(o);
113     if(p <= mid) return ask(p, l, mid, o << 1);
114     else return ask(p, mid + 1, r, o << 1 | 1);
115 }
116 
117 int getSum(int L, int R, int l, int r, int o) {
118     if(L <= l && r <= R) {
119         return sum[o];
120     }
121     pushdown(o);
122     int mid = (l + r) >> 1;
123     if(R <= mid) return getSum(L, R, l, mid, o << 1);
124     if(mid < L) return getSum(L, R, mid + 1, r, o << 1 | 1);
125     return getSum(L, R, l, mid, o << 1) + getSum(L, R, mid + 1, r, o << 1 | 1) + (rc[o << 1] != lc[o << 1 | 1]);
126 }
127 
128 inline int lca(int x, int y) {
129     while(top[x] != top[y]) {
130         if(d[top[x]] < d[top[y]])
131             y = fa[top[y]];
132         else
133             x = fa[top[x]];
134     }
135     return d[x] < d[y] ? x : y;
136 }
137 
138 inline int getLen(int x, int z) {
139     //printf("getLen %d %d \n", x, z);
140     int col = ask(pos[x], 1, n, 1), ans = 0;
141     while(top[x] != top[z]) {
142         ans += (col != ask(pos[x], 1, n, 1));
143         ans += getSum(pos[top[x]], pos[x], 1, n, 1);
144         //printf("x = %d top[x] = %d col = %d  ans = %d \n", x, top[x], col, ans);
145         col = ask(pos[top[x]], 1, n, 1);
146         x = fa[top[x]];
147     }
148     ans += (col != ask(pos[x], 1, n, 1));
149     //printf("%d != %d \n", col, ask(pos[x], 1, n, 1));
150     ans += getSum(pos[z], pos[x], 1, n, 1);
151     //printf("return ans = %d \n", ans);
152     return ans;
153 }
154 
155 inline void Change(int x, int y, int v) {
156     while(top[x] != top[y]) {
157         if(d[top[x]] > d[top[y]]) {
158             change(pos[top[x]], pos[x], v, 1, n, 1);
159             x = fa[top[x]];
160         }
161         else {
162             change(pos[top[y]], pos[y], v, 1, n, 1);
163             y = fa[top[y]];
164         }
165     }
166     if(d[x] < d[y]) std::swap(x, y);
167     change(pos[y], pos[x], v, 1, n, 1);
168     return;
169 }
170 
171 /// ------------------- tree 2 ----------------------
172 
173 inline void ADD(int x, int y) {
174     TP++;
175     EDGE[TP].v = y;
176     EDGE[TP].len = getLen(y, x);
177     //printf("getLen %d %d = %d \n", y, x, EDGE[TP].len);
178     EDGE[TP].nex = E[x];
179     E[x] = TP;
180     return;
181 }
182 
183 inline bool cmp(const int &a, const int &b) {
184     return pos[a] < pos[b];
185 }
186 
187 inline void work(int x) {
188     if(vis[x] == Time) return;
189     vis[x] = Time;
190     D[x] = E[x] = 0;
191     return;
192 }
193 
194 inline void build_t() {
195     TP = 0;
196     memcpy(imp + 1, imp2 + 1, K * sizeof(int));
197     std::sort(imp + 1, imp + K + 1, cmp);
198     stk[Top = 1] = imp[1];
199     work(imp[1]);
200     for(int i = 2; i <= K; i++) {
201         int x = imp[i], y = lca(x, stk[Top]);
202         work(x); work(y);
203         while(Top > 1 && d[y] <= d[stk[Top - 1]]) {
204             ADD(stk[Top - 1], stk[Top]);
205             Top--;
206         }
207         if(y != stk[Top]) {
208             ADD(y, stk[Top]);
209             stk[Top] = y;
210         }
211         stk[++Top] = x;
212     }
213     while(Top > 1) {
214         ADD(stk[Top - 1], stk[Top]);
215         Top--;
216     }
217     RT = stk[Top];
218     return;
219 }
220 
221 void dfs_1(int x) { /// DP 1
222     SIZ[x] = (use[x] == Time);
223     for(int i = E[x]; i; i = EDGE[i].nex) {
224         int y = EDGE[i].v;
225         dfs_1(y);
226         SIZ[x] += SIZ[y];
227     }
228     return;
229 }
230 
231 void dfs_2(int x) { /// DP 2
232     if(use[x] == Time) {
233         ans[x] = D[x];
234     }
235     for(int i = E[x]; i; i = EDGE[i].nex) {
236         int y = EDGE[i].v;
237         D[y] = D[x] + SIZ[y] * EDGE[i].len;
238         DEEP[y] = DEEP[x] + EDGE[i].len;
239         //printf("dfs_2 D %d = %lld * %lld = %lld \n", y, SIZ[y], EDGE[i].len, D[y]);
240         dfs_2(y);
241     }
242     return;
243 }
244 
245 inline void cal() {
246     build_t();
247     dfs_1(RT);
248     DEEP[RT] = 0;
249     dfs_2(RT);
250     return;
251 }
252 
253 int main() {
254     memset(tag, -1, sizeof(tag));
255     int q;
256     scanf("%d%d", &n, &q);
257     for(int i = 1; i <= n; i++) {
258         scanf("%d", &val[i]);
259     }
260     for(int i = 1, x, y; i < n; i++) {
261         scanf("%d%d", &x, &y);
262         add(x, y); add(y, x);
263     }
264     DFS_1(1, 0);
265     DFS_2(1, 1);
266     build(1, n, 1);
267 
268     for(int i = 1, f, x, y, z; i <= q; i++) {
269         scanf("%d%d", &f, &x);
270         if(f == 1) {
271             scanf("%d%d", &y, &z);
272             Change(x, y, z);
273         }
274         else {
275             Time++;
276             K = x;
277             for(int j = 1; j <= K; j++) {
278                 scanf("%d", &imp2[j]);
279                 use[imp2[j]] = Time;
280             }
281             cal();
282             LL SUM = 0;
283             for(int i = 1; i <= K; i++) {
284                 SUM += DEEP[imp2[i]];
285                 //printf("D %d = %lld \n", imp2[i], D[imp2[i]]);
286             }
287             //printf("SUM = %lld \n", SUM);
288             for(int i = 1; i <= K; i++) {
289                 printf("%lld ", SUM + K * DEEP[imp2[i]] - 2 * ans[imp2[i]] + K);
290             }
291             puts("");
292         }
293     }
294     return 0;
295 }
AC代码

 

posted @ 2019-03-10 14:53  huyufeifei  阅读(199)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

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