2019 ICPC 上海 F 題 A Simple Problem On A Tree

題目鏈接

題意

給出一棵 nn 個點的樹,每個點有點權。給出 qq 個操作,有 44 種操作:

  • (u,v)(u,v) 路徑上所有點點權置爲 ww
  • (u,v)(u,v) 路徑上所有點點權加上 ww
  • (u,v)(u,v) 路徑上所有點點權乘上 ww
  • (u,v)(u,v) 路徑上所有點點權 xWx3\sum_x{W_x^3} (立方和)。

題解

樹鏈剖分把樹上問題轉化爲序列上的問題,33 修改種操作使用 22 個標記就可以實現,都是 ×x+y\times x + y 的形式

  • 第一種操作視爲 ×0+w\times 0 + w
  • 第二種操作視爲 ×1+w\times 1 + w
  • 第三種操作視爲 ×w+0\times w + 0

所以維護和,平方和,立方和,乘法標記和加法標記即可。

#include <bits/stdc++.h>
#define lc rt << 1
#define rc rt << 1 | 1
using namespace std;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;

int top[N];
int son[N];
int fa[N];
int siz[N];
int dep[N];
int in[N];
int dfn[N];
int cnt;
vector<int> G[N];
int wt[N];
int lazyMul[N << 2];
int lazyAdd[N << 2];
int sum3[N << 2];
int sum2[N << 2];
int sum[N << 2];

void dfs1(int u, int f, int deep) {
    siz[u] = 1;
    fa[u] = f;
    dep[u] = deep;
    for (int v : G[u]) if (v != f) {
        dfs1(v, u, deep + 1);
        siz[u] += siz[v];
        if (!son[u] || siz[v] > siz[son[u]])
            son[u] = v;
    }
}
void dfs2(int u, int t) {
    in[u] = ++cnt;
    dfn[cnt] = u;
    top[u] = t;
    if (!son[u])
        return ;
    dfs2(son[u], t);
    for (int v : G[u]) if (v != fa[u] && v != son[u])
        dfs2(v, v);
}
inline void add(int &x, int y) { if ((x += y) >= mod) x -= mod; }
inline void mul(int &x, int y) { x = 1LL * x * y % mod; }
inline void solve(int rt, int x, int y, int num) {
    if (x != 1) {
        int w = x;
        int w2 = 1LL * x * x % mod;
        int w3 = 1LL * w2 * x % mod;

        mul(sum3[rt], w3);
        mul(sum2[rt], w2);
        mul(sum[rt], w);

        mul(lazyMul[rt], x);
        mul(lazyAdd[rt], x);
    }
    if (y != 0) {
        int w = y;
        int w2 = 1LL * y * y % mod;
        int w3 = 1LL * w2 * y % mod;

        add(sum3[rt], 1LL * num * w3 % mod);
        add(sum3[rt], 3LL * w * sum2[rt] % mod);
        add(sum3[rt], 3LL * w2 * sum[rt] % mod);

        add(sum2[rt], 1LL * num * w2 % mod);
        add(sum2[rt], 2LL * w * sum[rt] % mod);

        add(sum[rt], 1LL * num * w % mod);

        add(lazyAdd[rt], y);
    }
}
inline void pushUp(int rt) {
    sum[rt] = (sum[lc] + sum[rc]) % mod;
    sum2[rt] = (sum2[lc] + sum2[rc]) % mod;
    sum3[rt] = (sum3[lc] + sum3[rc]) % mod;
}
inline void pushDown(int rt, int ln, int rn) {
    int x = lazyMul[rt];
    int y = lazyAdd[rt];
    solve(lc, x, y, ln);
    solve(rc, x, y, rn);
    lazyMul[rt] = 1;
    lazyAdd[rt] = 0;
}
void build(int L, int R, int rt) {
    lazyMul[rt] = 1;
    lazyAdd[rt] = 0;
    if (L == R) {
        int w = wt[dfn[L]];
        sum[rt] = w;
        sum2[rt] = 1LL * w * w % mod;
        sum3[rt] = 1LL * w * w % mod * w % mod;
        return ;
    }
    int mid = L + R >> 1;
    build(L, mid, lc);
    build(mid + 1, R, rc);
    pushUp(rt);
}
void update(int L, int R, int l, int r, int x, int y, int rt) {
    if (l <= L && R <= r) {
        solve(rt, x, y, R - L + 1);
        return ;
    }
    int mid = L + R >> 1;
    pushDown(rt, mid - L + 1, R - mid);
    if (l <= mid)
        update(L, mid, l, r, x, y, lc);
    if (r > mid)
        update(mid + 1, R, l, r, x, y, rc);
    pushUp(rt);
}
int query(int L, int R, int l, int r, int rt) {
    if (l <= L && R <= r)
        return sum3[rt];
    int mid = L + R >> 1;
    pushDown(rt, mid - L + 1, R - mid);
    int res = 0;
    if (l <= mid)
        add(res, query(L, mid, l, r, lc));
    if (r > mid)
        add(res, query(mid + 1, R, l, r, rc));
    pushUp(rt);
    return res;
}
void update(int u, int v, int x, int y) {
    for (; top[u] != top[v];) {
        if (dep[top[u]] < dep[top[v]])
            swap(u, v);
        update(1, cnt, in[top[u]], in[u], x, y, 1);
        u = fa[top[u]];
    }
    if (dep[u] > dep[v])
        swap(u, v);
    update(1, cnt, in[u], in[v], x, y, 1);
}
int query(int u, int v) {
    int res = 0;
    for (; top[u] != top[v];) {
        if (dep[top[u]] < dep[top[v]])
            swap(u, v);
        add(res, query(1, cnt, in[top[u]], in[u], 1));
        u = fa[top[u]];
    }
    if (dep[u] > dep[v])
        swap(u, v);
    add(res, query(1, cnt, in[u], in[v], 1));
    return res;
}

int main() {
#ifdef purple_bro
    freopen("in.txt", "r", stdin);
#endif // purple_bro
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    int cas = 0;

    cin >> T;

    for (; T--;) {
        cout << "Case #" << ++cas << ":\n";

        int n;
        cnt = 0;

        cin >> n;

        for (int i = 0; i < n - 1; ++i) {
            int u, v;
            cin >> u >> v;
            G[u].emplace_back(v);
            G[v].emplace_back(u);
        }

        for (int i = 1; i <= n; ++i)
            cin >> wt[i];

        dfs1(1, 1, 1);
        dfs2(1, 1);
        build(1, cnt, 1);

        int q;

        cin >> q;

        for (int i = 0; i < q; ++i) {
            int op, u, v, w;
            cin >> op;
            if (op == 4) {
                cin >> u >> v;
                cout << query(u, v) << "\n";
            } else {
                cin >> u >> v >> w;
                if (op == 1)
                    update(u, v, 0, w);
                else if (op == 2)
                    update(u, v, 1, w);
                else
                    update(u, v, w, 0);
            }
        }

        for (int i = 1; i <= n; ++i) {
            son[i] = 0;
            G[i].clear();
        }
    }

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章