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