day-21
树链剖分 + 线段树 模板
const int maxn = 1e5 + 7;
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
int n, t, m, w[maxn];
vector<int> mp[maxn];
string op;
int cnt, dep[maxn], fa[maxn], siz[maxn], son[maxn], top[maxn], dfn[maxn], rnk[maxn];
struct tree {
int ma[maxn << 2], sum[maxn << 2], a[maxn];
void push_up(int p) {
ma[p] = max(ma[ls(p)], ma[rs(p)]);
sum[p] = sum[ls(p)] + sum[rs(p)];
}
void build(int p, int l, int r) {
if (l == r) {
sum[p] = ma[p] = a[l];
return;
}
int mi = (l + r) >> 1;
build(ls(p), l, mi);
build(rs(p), mi + 1, r);
push_up(p);
}
void update(int p, int l, int r, int pl, int k) {
if (l == r) {
ma[p] = sum[p] = k;
return;
}
int mi = (l + r) >> 1;
if (pl <= mi)
update(ls(p), l, mi, pl, k);
else
update(rs(p), mi + 1, r, pl, k);
push_up(p);
return;
}
int query_max(int p, int L, int R, int l, int r) {
if (L <= l && r <= R)
return ma[p];
int mi = (l + r) >> 1, ans = -1e9;
if (L <= mi)
ans = max(ans, query_max(ls(p), L, R, l, mi));
if (R > mi)
ans = max(ans, query_max(rs(p), L, R, mi + 1, r));
return ans;
}
int query_sum(int p, int L, int R, int l, int r) {
if (L <= l && r <= R)
return sum[p];
int mi = (l + r) >> 1, ans = 0;
if (L <= mi)
ans += query_sum(ls(p), L, R, l, mi);
if (R > mi)
ans += query_sum(rs(p), L, R, mi + 1, r);
return ans;
}
} tr;
void dfs(int u) {
siz[u] = 1;
son[u] = -1;
for (auto v : mp[u]) {
if (dep[v])
continue;
dep[v] = dep[u] + 1;
fa[v] = u;
dfs(v);
siz[u] += siz[v];
if (son[u] == -1 || siz[v] > siz[son[u]])
son[u] = v;
}
}
void dfs(int u, int tp) {
if (cnt >= n)
return;
top[u] = tp;
dfn[u] = ++cnt;
rnk[cnt] = u;
if (son[u] == -1)
return;
dfs(son[u], tp);
for (auto v : mp[u])
if (v != son[u] && v != fa[u])
dfs(v, v);
}
void treeLinkSplit() {
dep[1] = 1;
dfs(1);
dfs(1, 1);
}
int path_max(int x, int y) {
int ans = -1e9;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]])
swap(x, y);
ans = max(ans, tr.query_max(1, dfn[top[x]], dfn[x], 1, n));
x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x, y);
ans = max(ans, tr.query_max(1, dfn[x], dfn[y], 1, n));
return ans;
}
int path_sum(int x, int y) {
int ans = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]])
swap(x, y);
ans += tr.query_sum(1, dfn[top[x]], dfn[x], 1, n);
x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x, y);
ans += tr.query_sum(1, dfn[x], dfn[y], 1, n);
return ans;
}
void solve() {
cin >> n;
for (int i = 1, u, v; i <= n - 1; i++) {
cin >> u >> v;
mp[u].push_back(v);
mp[v].push_back(u);
}
treeLinkSplit();
for (int i = 1; i <= n; i++)
cin >> tr.a[dfn[i]];
cin >> m;
tr.build(1, 1, n);
for (int i = 1, x, y; i <= m; i++) {
cin >> op >> x >> y;
if (op.back() == 'X') {
cout << path_max(x, y) << endl;
} else if (op.back() == 'M') {
cout << path_sum(x, y) << endl;
} else {
tr.update(1, 1, n, dfn[x], y);
}
}
}
区间修改 -> 子树修改 + 路径修改
#define int long long
const int maxn = 1e5 + 7;
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
vector<int> mp[maxn];
int dep[maxn], siz[maxn], fa[maxn], son[maxn];
int top[maxn], dfn[maxn], rnk[maxn], cnt;
int n, m, r, p;
struct tree {
int sum[maxn << 2], ma[maxn << 2], a[maxn << 2], lz[maxn << 2];
void push_up(int p) {
sum[p] = sum[ls(p)] + sum[rs(p)];
ma[p] = max(ma[ls(p)], ma[rs(p)]);
}
void push_down(int p, int l, int r) {
lz[ls(p)] += lz[p];
lz[rs(p)] += lz[p];
int len = (r - l + 1);
sum[ls(p)] += (len - len / 2) * lz[p];
sum[rs(p)] += (len / 2) * lz[p];
lz[p] = 0;
}
void build(int p, int l, int r) {
if (l == r) {
sum[p] = ma[p] = a[rnk[l]];
return;
}
build(ls(p), l, (l + r) >> 1);
build(rs(p), ((l + r) >> 1) + 1, r);
push_up(p);
}
void update(int p, int l, int r, int L, int R, int x) {
if (L <= l && r <= R) {
lz[p] += x;
sum[p] += (r - l + 1) * x;
return;
}
if (lz[p]) push_down(p, l, r);
if (L <= ((l + r) >> 1)) update(ls(p), l, (l + r) >> 1, L, R, x);
if (((l + r) >> 1) < R) update(rs(p), ((l + r) >> 1) + 1, r, L, R, x);
push_up(p);
}
int query_sum(int p, int L, int R, int l, int r) {
if (L <= l && r <= R) return sum[p];
if (lz[p]) push_down(p, l, r);
int mi = (l + r) >> 1, res = 0;
if (L <= mi) res += query_sum(ls(p), L, R, l, mi);
if (R > mi) res += query_sum(rs(p), L, R, mi + 1, r);
return res;
}
int query_max(int p, int L, int R, int l, int r) {
if (L <= l && r <= R) return ma[p];
int res = -1e9, mi = (l + r) >> 1;
if (L <= mi) res = max(res, query_max(ls(p), L, R, l, mi));
if (R > mi) res = max(res, query_max(rs(p), L, R, mi + 1, r));
return res;
}
} tr;
void dfs(int u) {
siz[u] = 1;
son[u] = -1;
for (auto v : mp[u]) {
if (dep[v])
continue;
dep[v] = dep[u] + 1;
fa[v] = u;
dfs(v);
siz[u] += siz[v];
if (son[u] == -1 || siz[v] > siz[son[u]])
son[u] = v;
}
}
void dfs(int u, int tp) {
if (cnt >= n)
return;
top[u] = tp;
dfn[u] = ++cnt;
rnk[cnt] = u;
if (son[u] == -1) return;
dfs(son[u], tp);
for (auto v : mp[u])
if (v != son[u] && v != fa[u])
dfs(v, v);
}
void tree_init(int o = 1) {
dep[o] = 1;
dfn[o] = 1;
dfs(o);
dfs(o, o);
}
int path_max(int u, int v) {
int ans = -1e9;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
ans = max(ans, tr.query_max(1, dfn[top[u]], dfn[u], 1, n));
u = fa[top[u]];//不重复走
}
if (dep[u] > dep[v])swap(u, v);
ans = max(ans, tr.query_max(1, dfn[u], dfn[v], 1, n));
return ans;
}
int path_sum(int u, int v) {
int ans = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
ans += tr.query_sum(1, dfn[top[u]], dfn[u], 1, n);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
ans += tr.query_sum(1, dfn[u], dfn[v], 1, n);
return ans;
}
void path_update(int u, int v, int x) {
int ans = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
tr.update(1, 1, n, dfn[top[u]], dfn[u], x);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
tr.update(1, 1, n, dfn[u], dfn[v], x);
}
void tree_update(int p, int x) {
tr.update(1, 1, n, dfn[p], dfn[p] + siz[p] - 1, x);
}
int tree_max(int u) {
return tr.query_max(1, dfn[u], dfn[u] + siz[u] - 1, 1, n);
}
int tree_sum(int u) {
return tr.query_sum(1, dfn[u], dfn[u] + siz[u] - 1, 1, n);
}
int a[maxn];
void solve() {
cin >> n >> m >> r >> p;
for (int i = 1; i <= n; i++)
cin >> tr.a[i];
for (int i = 1, u, v; i <= n - 1; i++) {
cin >> u >> v;
mp[u].push_back(v);
mp[v].push_back(u);
}
tree_init(r);
tr.build(1, 1, n);
for (int i = 1, op, x, y, z; i <= m; i++) {
cin >> op;
if (op == 1) {
cin >> x >> y >> z;
path_update(x, y, z);
} else if (op == 2) {
cin >> x >> y;
cout << path_sum(x, y) % p << endl;
} else if (op == 3) {
cin >> x >> y;
tree_update(x, y);
} else {
cin >> x;
cout << tree_sum(x) % p << endl;
}
}
}
线段树动态开点 + 树链剖分
int n, q, w[maxn], c[maxn];
vector<int> mp[maxn];
int dep[maxn], fa[maxn], siz[maxn], son[maxn];
void dfs(int u) {
siz[u] = 1;
son[u] = -1;
for (auto v:mp[u]) {
if (dep[v]) continue;
dep[v] = dep[u] + 1;
fa[v] = u;
dfs(v);
siz[u] += siz[v];
if (son[u] == -1 || siz[v] > siz[son[u]])
son[u] = v;
}
}
int cnt, dfn[maxn], top[maxn], rnk[maxn];
void dfs(int u, int tp) {
dfn[u] = ++cnt;
top[u] = tp;
rnk[cnt] = u;
if (son[u] != -1)
dfs(son[u], tp);
for (auto v :mp[u])
if (v != fa[u] && v != son[u])
dfs(v, v);
}
int tot, rt[maxn];
struct node {
int l, r, sum, max;
} tr[maxn * 200];
void update(int &p, int l, int r, int pl, int val) {
if (!p) p = ++tot;
tr[p].max = max(tr[p].max, val), tr[p].sum += val;
if (l == r) return;
int mi = (l + r) >> 1;
if (pl <= mi) update(tr[p].l, l, mi, pl, val);
else update(tr[p].r, mi + 1, r, pl, val);
}
void del(int &p, int l, int r, int pl) {
if (l == r) {
tr[p].max = tr[p].sum = 0;
return;
}
int mi = (l + r) >> 1;
if (pl <= mi) del(tr[p].l, l, mi, pl);
else del(tr[p].r, mi + 1, r, pl);
tr[p].max = max(tr[tr[p].l].max, tr[tr[p].r].max);
tr[p].sum = tr[tr[p].l].sum + tr[tr[p].r].sum;
}
int query_max(int p, int l, int r, int L, int R) {
if (L <= l && r <= R) return tr[p].max;
int mi = (l + r) >> 1, ret = 0;
if (L <= mi) ret = max(ret, query_max(tr[p].l, l, mi, L, R));
if (R > mi) ret = max(ret, query_max(tr[p].r, mi + 1, r, L, R));
return ret;
}
int query_sum(int p, int l, int r, int L, int R) {
if (L <= l && r <= R) return tr[p].sum;
int mi = (l + r) >> 1, res = 0;
if (L <= mi) res += query_sum(tr[p].l, l, mi, L, R);
if (R > mi) res += query_sum(tr[p].r, mi + 1, r, L, R);
return res;
}
int path_sum(int u, int v, int k) {
int res = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
res += query_sum(rt[k], 1, n, dfn[top[u]], dfn[u]);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
res += query_sum(rt[k], 1, n, dfn[u], dfn[v]);
return res;
}
int path_max(int u, int v, int k) {
int res = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
res = max(res, query_max(rt[k], 1, n, dfn[top[u]], dfn[u]));
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
res = max(res, query_max(rt[k], 1, n, dfn[u], dfn[v]));
return res;
}
void solve() {
cin >> n >> q;
for (int i = 1; i <= n; i++)
cin >> w[i] >> c[i];
for (int i = 1, u, v; i <= n - 1; i++) {
cin >> u >> v;
mp[u].push_back(v), mp[v].push_back(u);
}
dep[1] = 1;
dfs(1), dfs(1, 1);
for (int i = 1; i <= n; i++)
update(rt[c[i]], 1, n, dfn[i], w[i]);
char op[10];
for (int i = 1, x, y; i <= q; i++) {
cin >> op >> x >> y;
if (op[1] == 'S') {
cout << path_sum(x, y, c[x]) << endl;
} else if (op[1] == 'M') {
cout << path_max(x, y, c[x]) << endl;
} else if (op[1] == 'W') {
del(rt[c[x]], 1, n, dfn[x]);
update(rt[c[x]], 1, n, dfn[x], y);
w[x] = y;
} else if (op[1] == 'C') {
del(rt[c[x]], 1, n, dfn[x]);
update(rt[y], 1, n, dfn[x], w[x]);
c[x] = y;
}
}
}
我看见 你