[AtCoder Beginner Contest 133]F - Colorful Tree
写完题去网上逛一圈发现全都是离线LCA,Orz。
大致题意是一颗树上边有边权和颜色,每次询问会先把颜色为x的边的边权变为y,再询问u到v的边权和。注意,每次询问的修改只针对当前询问。
由于题目是树上距离,所以树剖大致是可以做的。
树剖完后将每条边的边权转点权,赋给深度较高的节点。
每次查询,我们只要知道两点的权值和$sum1$,颜色为$x$的边的权值和$sum2$以及颜色为$x$的边的个数$num$,则答案为$sum1-sum2+num*y$。
所以就建权值线段树,以颜色为权值,同时维护颜色个数以及这种颜色的权值和。
就是普普通通的树剖主席树啦QAQ
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 3e5 + 10; 4 typedef long long ll; 5 struct node { 6 int s, e, c, w, next; 7 }edge[maxn]; 8 int head[maxn], len; 9 int n, q; 10 void init() { 11 memset(head, -1, sizeof(head)); 12 len = 0; 13 } 14 void add(int s, int e, int c, int w) { 15 edge[len].s = s;edge[len].e = e; 16 edge[len].w = w;edge[len].c = c; 17 edge[len].next = head[s]; 18 head[s] = len++; 19 } 20 int son[maxn], top[maxn], tid[maxn], fat[maxn], siz[maxn], dep[maxn], rak[maxn]; 21 int dfx; 22 void dfs1(int x, int fa, int d) { 23 siz[x] = 1, son[x] = -1, fat[x] = fa, dep[x] = d; 24 for (int i = head[x]; i != -1; i = edge[i].next) { 25 int y = edge[i].e; 26 if (y == fa) 27 continue; 28 dfs1(y, x, d + 1); 29 siz[x] += siz[y]; 30 if (son[x] == -1 || siz[y] > siz[son[x]]) 31 son[x] = y; 32 } 33 } 34 void dfs2(int x, int c) { 35 top[x] = c; tid[x] = ++dfx; rak[dfx] = x; 36 if (son[x] == -1) 37 return; 38 dfs2(son[x], c); 39 for (int i = head[x]; i != -1; i = edge[i].next) { 40 int y = edge[i].e; 41 if (y == fat[x] || y == son[x]) 42 continue; 43 dfs2(y, y); 44 } 45 } 46 int cnt, root[maxn], ls[maxn * 40], rs[maxn * 40], num[maxn * 40], val[maxn * 40]; 47 struct C { 48 int color, dis; 49 }a[maxn]; 50 void build(C k, int l, int r, int& i) { 51 num[++cnt] = num[i] + 1, val[cnt] = val[i] + k.dis, ls[cnt] = ls[i], rs[cnt] = rs[i]; 52 i = cnt; 53 if (l == r) 54 return; 55 int mid = l + r >> 1; 56 if (k.color <= mid) 57 build(k, l, mid, ls[i]); 58 else 59 build(k, mid + 1, r, rs[i]); 60 } 61 C query(int u, int v, int k, int l, int r) { 62 if (l == r) 63 return { num[v] - num[u],val[v] - val[u] }; 64 int mid = l + r >> 1; 65 if (k <= mid) 66 return query(ls[u], ls[v], k, l, mid); 67 else 68 return query(rs[u], rs[v], k, mid + 1, r); 69 } 70 int solve(int cr, int dis, int x, int y) { 71 C ans = { 0,0 }; 72 int sum = 0; 73 while (top[x] != top[y]) { 74 if (dep[top[x]] < dep[top[y]]) 75 swap(x, y); 76 C t = query(root[tid[top[x]] - 1], root[tid[x]], cr, 1, n); 77 sum += val[root[tid[x]]] - val[root[tid[top[x]] - 1]]; 78 ans.color += t.color, ans.dis += t.dis; 79 x = fat[top[x]]; 80 } 81 82 if (x != y) { 83 if (dep[x] < dep[y]) 84 swap(x, y); 85 C t = query(root[tid[son[y]] - 1], root[tid[x]], cr, 1, n); 86 sum += val[root[tid[x]]] - val[root[tid[son[y]] - 1]]; 87 ans.color += t.color, ans.dis += t.dis; 88 } 89 return sum - ans.dis + ans.color * dis; 90 } 91 int main() { 92 scanf("%d%d", &n, &q); 93 init(); 94 for (int i = 1, x, y, c, d; i < n; i++) { 95 scanf("%d%d%d%d", &x, &y, &c, &d); 96 add(x, y, c, d); 97 add(y, x, c, d); 98 } 99 dfs1(1, 0, 1); 100 dfs2(1, 1); 101 for (int i = 0; i < len; i += 2) { 102 int x = edge[i].e; 103 int y = edge[i].s; 104 if (dep[x] < dep[y]) 105 swap(x, y); 106 a[tid[x]] = { edge[i].c, edge[i].w }; 107 } 108 for (int i = 2; i <= dfx; i++) { 109 root[i] = root[i - 1]; 110 build(a[i], 1, n, root[i]); 111 } 112 while (q--) { 113 int x, y, u, v; 114 scanf("%d%d%d%d", &x, &y, &u, &v); 115 printf("%d\n", solve(x, y, u, v)); 116 } 117 }