[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 }

 

posted @ 2019-09-20 14:43  祈梦生  阅读(282)  评论(0编辑  收藏  举报