• 「题解」洛谷 P4074 [WC2013]糖果公园


    题目

    P4074 [WC2013]糖果公园

    简化题意

    给你一棵树树,点有点权,带修改,每一次经过一种点权会有不同的贡献(随着经过次数再变),问你从一个点到一个点的贡献和

    思路

    树上带修莫队。

    (cnt[i]) 表示 (i) 这个点的权值的出现次数。

    (a[i]) 表示 (i) 号点的权值。

    (v[i]) 表示一权值 (i) 的贡献定值。

    (v[i]) 表示一权值出现 (i) 次时的贡献常数。

    加入一个点 (u)ans += v[++cnt[a[u]]] * w[a[u]]

    删掉一个点 (u)ans -= v[cnt[a[u]]--] * w[a[u]]

    先考虑没有修改,因为加一个点和删一个点都可以 (O(1)) 维护,所以莫队没问题。

    在树上,树上莫队。

    如果没有修改就是一个普通的树上莫队。有修改就是树上带修莫队了。

    Code

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #define MAXN 100001
    
    inline void read(int &T) {
        int x = 0;
        bool f = 0;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-') f = !f;
            c = getchar();
        }
        while (c >= '0' && c <= '9') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        T = f ? -x : x;
    }
    
    void write(long long x) {
        if (x < 0) putchar('-'), write(-x);
        else {
            if (x / 10) write(x / 10);
            putchar(x % 10 + '0');
        }
    }
    
    typedef long long ll;
    ll ans[MAXN];
    int n, m, s, sqrn, pthn, head[MAXN], a[MAXN], v[MAXN], w[MAXN], num[MAXN << 1], cnt[MAXN], vis[MAXN];
    int c_, cc, cq, fir[MAXN], la[MAXN], pre[MAXN << 1], dep[MAXN], lg[MAXN], fa[MAXN][21];
    struct change {
        int w, pos;
    }c[MAXN];
    struct query {
        int x, y, t, lca, id;
        friend bool operator < (query q1, query q2) {
            if (num[q1.x] != num[q2.x]) return num[q1.x] < num[q2.x];
            if (num[q1.y] != num[q2.y]) return num[q1.y] < num[q2.y];
            return q1.t < q2.t;
        }
    }q[MAXN];
    struct Edge {
        int next ,to;
    }pth[MAXN << 1];
    
    void add(int from, int to) {
        pth[++pthn].to = to, pth[pthn].next = head[from];
        head[from] = pthn;
    }
    
    void dfs(int u, int father) {
        fa[u][0] = father, dep[u] = dep[father] + 1;
        fir[u] = ++c_, pre[c_] = u;
        for (int i = head[u]; i; i = pth[i].next) {
            int x = pth[i].to;
            if (x != father) dfs(x, u);
        }
        la[u] = ++c_, pre[c_] = u;
    }
    
    int lca(int x, int y) {
        if (dep[x] < dep[y]) std::swap(x, y);
        while (dep[x] > dep[y]) {
            x = fa[x][lg[dep[x] - dep[y]] - 1];
        }
        if (x == y) return x;
        for (int k = lg[dep[x]] - 1; k >= 0; --k) {
            if (fa[x][k] != fa[y][k]) {
                x = fa[x][k];
                y = fa[y][k];
            }
        }
        return fa[x][0];
    }
    
    void work(int now, ll &ans) {
        if (vis[now]) {
            ans -= 1ll * w[cnt[a[now]]] * v[a[now]];
            --cnt[a[now]];
        }
        else {
            ++cnt[a[now]];
            ans += 1ll * w[cnt[a[now]]] * v[a[now]];
        }
        vis[now] ^= 1;
    }
    
    bool okay(int nq, int node) {
        bool flag1 = (fir[node] >= q[nq].x && fir[node] <= q[nq].y && (la[node] < q[nq].x || la[node] > q[nq].y));
        bool flag2 = (la[node] >= q[nq].x && la[node] <= q[nq].y && (fir[node] < q[nq].x || fir[node] > q[nq].y));
        return (flag1 || flag2);
    }
    
    int main() {
        read(n), read(m), read(s), sqrn = pow(2 * n, 2.0 / 3.0);
        for (int i = 1; i <= 2 * n; ++i) num[i] = (i - 1) / sqrn + 1;
        for (int i = 1; i <= m; ++i) read(v[i]);
        for (int i = 1; i <= n; ++i) read(w[i]);
        for (int i = 1, u, v; i < n; ++i) {
            read(u), read(v);
            add(u, v), add(v, u);
        }
        dfs(1, 0);
        for (int i = 1; i <= n; ++i) {
            lg[i] = lg[i - 1] + ((1 << lg[i - 1]) == i);
        }
        for (int j = 1; (1 << j) <= n; ++j) {
            for (int i = 1; i <= n; ++i) {
                fa[i][j] = fa[fa[i][j - 1]][j - 1];
            }
        }
        for (int i = 1; i <= n; ++i) read(a[i]);
        for (int i = 1, opt, x, y, f; i <= s; ++i) {
            read(opt), read(x), read(y);
            if (opt == 1) {
                f = lca(x, y), q[++cq].id = cq, q[cq].t = cc;
                if (fir[x] > fir[y]) std::swap(x, y);
                if (x == f) {
                    q[cq].x = fir[x];
                    q[cq].y = fir[y];
                }
                else {
                    q[cq].x = la[x];
                    q[cq].y = fir[y];
                    q[cq].lca = f;
                }
            }
            else c[++cc].w = y, c[cc].pos = x;
        }
        std::sort(q + 1, q + cq + 1);
        int l = 1, r = 0, t = 0;
        ll now = 0;
        for (int i = 1; i <= cq; ++i) {
            while (l > q[i].x) work(pre[--l], now);
            while (r < q[i].y) work(pre[++r], now);
            while (l < q[i].x) work(pre[l++], now);
            while (r > q[i].y) work(pre[r--], now);
            while (t < q[i].t) {
                ++t;
                bool flag = okay(i, c[t].pos);
                if (flag) work(c[t].pos, now);
                std::swap(a[c[t].pos], c[t].w);
                if (flag) work(c[t].pos, now);
            }
            while (t > q[i].t) {
                bool flag = okay(i, c[t].pos);
                if (flag) work(c[t].pos, now);
                std::swap(a[c[t].pos], c[t].w);
                if (flag) work(c[t].pos, now);
                --t;
            }
            if (q[i].lca) work(q[i].lca, now);
            ans[q[i].id] = now;
            if (q[i].lca) work(q[i].lca, now);
        }
        for (int i = 1; i <= cq; ++i) {
            write(ans[i]);
            puts("");
        }
        return 0;
    }
    
  • 相关阅读:
    python验证卡普耶卡(D.R.Kaprekar)6174猜想
    关于java环境变量配置出现javac命令无法运行的解决办法
    关于QQ农场牧场等曾经流行的游戏的一些见解
    个人博客九
    个人博客八
    个人博客七
    个人博客六
    第十一周学习进度
    个人博客五
    个人博客四
  • 原文地址:https://www.cnblogs.com/poi-bolg-poi/p/13594940.html
Copyright © 2020-2023  润新知