[2021 HDU中超 第二场 B] I love tree

HDU寄了,当树剖板子了
题意:
对树上路径的点权加递增的平方,询问点权。

思路:
优先考虑树链剖分+线段树。剖完后子区间内是连续的,考虑构造\((dfn_i - x)^2\)或者\((x - dfn_i)^2\),就能做到递增的平方了。两个式子展开来是一样的,考虑\(3\)\(lazy\)标记分别记录。

#include <bits/stdc++.h>
using namespace std;

#define endl "\n"

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 7;
#define ls (id << 1)
#define rs (id << 1 | 1)
#define mid (l + r >> 1)

int f[N], bos[N], par[N][20], sz[N], bigSon[N], dfn[N], dep[N];
vector<int> G[N];
int tot, n, q;

struct Seg {
    ll t[3][N << 2];
    void init() {
        memset(t, 0, sizeof(t));
    }
    void down(int id) {
        for (int i = 0; i < 3; ++i) {
            t[i][ls] += t[i][id];
            t[i][rs] += t[i][id];
            t[i][id] = 0;
        }
    }
    void modify(int id, int l, int r, int ql, int qr, ll x) {
        if (l >= ql && r <= qr) {
            t[0][id]++;
            t[1][id] += 2 * x;
            t[2][id] += x * x;
            return;
        }
        down(id);
        if (ql <= mid) modify(ls, l, mid, ql, qr, x);
        if (qr > mid) modify(rs, mid + 1, r, ql, qr, x);
    }
    ll query(int id, int l, int r, int p) {
        if (l == r) {
            return t[0][id] * l * l - t[1][id] * l + t[2][id];
        }
        down(id);
        if (p <= mid) return query(ls, l, mid, p);
        else return query(rs, mid + 1, r, p);
    }
}seg;

void dfs1(int u, int fa) {
    f[u] = fa;
    sz[u] = 1;
    dep[u] = dep[fa] + 1;
    par[u][0] = fa;
    for (int i = 1; i < 20; ++i) {
        par[u][i] = par[ par[u][i - 1] ][i - 1];
    }
    for (auto v : G[u]) {
        if (v == fa) continue;
        dfs1(v, u);
        sz[u] += sz[v];
        if (sz[v] > sz[ bigSon[u] ]) bigSon[u] = v;
    }
}

void dfs2(int u, int fa, int t) {
    bos[u] = t;
    dfn[u] = ++tot;
    if (!bigSon[u]) return;
    dfs2(bigSon[u], u, t);
    for (auto v : G[u]) {
        if (v == fa) continue;
        if (v != bigSon[u]) dfs2(v, u, v);
    }
}

int lca(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    for (int i = 19; i >= 0; --i) {
        if (dep[ par[u][i] ] >= dep[v]) u = par[u][i];
    }
    if (u == v) return u;
    for (int i = 19; i >= 0; --i) {
        if (par[u][i] != par[v][i]) {
            u = par[u][i];
            v = par[v][i];
        }
    }
    return par[u][0];
}

void gao(int l, int r) {
    int ff = lca(l, r);
    int fl = bos[l], fr = bos[r];
    int x;
    int st = 1, ed = dep[l] + dep[r] - 2 * dep[ff] + 1;
    while (fl != fr) {
        if (dep[fl] >= dep[fr]) {
            seg.modify(1, 1, n, dfn[fl], dfn[l], dfn[l] + st);
            st += dep[l] - dep[fl] + 1;
            l = f[fl], fl = bos[l];
        } else {
            seg.modify(1, 1, n, dfn[fr], dfn[r], dfn[fr] - (ed - (dep[r] - dep[fr])));
            ed -= dep[r] - dep[fr] + 1;
            r = f[fr], fr = bos[r];
        }
    }
    int ql = min(dfn[l], dfn[r]), qr = max(dfn[l], dfn[r]);
    if (dfn[l] >= dfn[r]) x = qr + st;
    else x = ql - (ed - (dep[r] - dep[l]));
    seg.modify(1, 1, n, ql, qr, x);
}

void solve() {
    seg.init();
    cin >> n;
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs1(1, 0);
    dfs2(1, 0, 1);
    cin >> q;
    int op, l, r;
    while (q--) {
        cin >> op;
        if (op == 1) {
            cin >> l >> r;
            gao(l, r);
        } else {
            cin >> l;
            cout << seg.query(1, 1, n, dfn[l]) << endl;
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    cout << fixed << setprecision(20);
    int t = 1;
    while (t--) solve();
    return 0;
}
posted @ 2022-01-22 21:32  stff577  阅读(41)  评论(0编辑  收藏  举报