Dec. 30th 2025
今年最后一次竞赛课
DFS 序4


思路很简单
将一条链的信息存储至一个点上
信息设计
-
节点信息:
不存储
-
tag信息:- (只改节点的)
tag1 - (改子树的):
tag2:\(\to\)ans += (depth[x] + 1) * tree[id].tag2tag3:\(\to\)ans -= tree[id].tag3
- (只改节点的)
封闭性:显然(若只存储后面两个则会丢失单点权值修改的信息)
代码 没有调
#include<bits/stdc++.h>
using namespace std;
using lf = double;
using ll = long long;
using ull = unsigned long long;
using pii = pair<ll, int>;
int read() {
int k = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')k = k * 10 + c - '0', c = getchar();
return k * f;
}
void print(ll x) {
if (x < 0)putchar('-'), x = -x;
if (x < 10)putchar(x + '0');
else print(x / 10), putchar(x % 10 + '0');
}
const int maxn = 1e6 + 5;
ll ls(ll i) {return i << 1;}
ll rs(ll i) {return i << 1 | 1;}
int n, m, root, id;
ll a[maxn];
//ll tree[maxn << 2], tag1[maxn << 2], tag2[maxn << 2], tag3[maxn << 2];
ll depth[maxn];
ll in[maxn], out[maxn], dfs[maxn]; // dfn + out + dfs
bool vis[maxn];
vector<int> adj[maxn];
int v[maxn];
struct sgt{
int t1, t2, t3;
int sum; // useless
} tree[maxn << 2];
void maintain(int id) { // push up
tree[id].sum = ~~(0 + 0);
}
void build(int id, int left, int right) {
if (left == right) {
// tree[id] = v[dfs[left]];
return;
}
ll mid = (left + right) >> 1;
build(ls(id), left, mid);
build(rs(id), mid + 1, right);
maintain(id);
}
void addtag(ll d, int id, int left, int right) {
return tree[id].t1 += d, void();
}
void addtag2(ll d, int id, int left, int right) {
return tree[id].t2 += d, void();
}
void addtag3(ll d, int id, int left, int right) {
return tree[id].t3 += d * depth[dfs[id]], void();
}
void pushdown(int id, int left, int right, int d = 0) {
if (tree[id].t1) {
ll mid = (left + right) >> 1;
addtag(tree[id].t1, ls(id), left, mid);
addtag(tree[id].t1, rs(id), mid + 1, right);
tree[id].t1 = 0;
}
if (tree[id].t2) {
ll mid = (left + right) >> 1;
addtag2(tree[id].t2, ls(id), left, mid);
addtag2(tree[id].t2, rs(id), mid + 1, right);
tree[id].t2 = 0;
}
if (tree[id].t3) {
ll mid = (left + right) >> 1;
addtag3(tree[id].t3, ls(id), left, mid);
addtag3(tree[id].t3, rs(id), mid + 1, right);
tree[id].t3 = 0;
}
}
void update_p(int L, int R, ll d, int id = 1, int left = 1, int right = n) {
if (L <= left && right <= R) {
addtag(d, id, left, right);
return;
}
pushdown(id, left, right);
ll mid = (left + right) >> 1;
if (L <= mid) update_p(L, R, d, ls(id), left, mid);
if (R > mid) update_p(L, R, d, rs(id), mid + 1, right);
maintain(id);
}
void update_r(int L, int R, ll d, int id = 1, int left = 1, int right = n) {
if (L <= left && right <= R) {
addtag2(d, id, left, right);
return;
}
pushdown(id, left, right);
ll mid = (left + right) >> 1;
if (L <= mid) update_r(L, R, d, ls(id), left, mid);
if (R > mid) update_r(L, R, d, rs(id), mid + 1, right);
maintain(id);
}
sgt query(ll posi, int id = 1, int left = 1, int right = n) { // point query
if (left == right)
return tree[id];
pushdown(id, left, right);
ll mid = (left + right) >> 1;
if (posi <= mid) return query(posi, ls(id), left, mid);
else return query(posi, rs(id), mid + 1, right);
}
void DFS(int u) { // init
in[u] = ++id;
dfs[id] = u;
vis[u] = true;
for (int v : adj[u])
if (!vis[v]) {
depth[v] = depth[u] + 1;
DFS(v);
}
out[u] = id;
}
struct node{ // lca queries
int p, id;
node() = default;
node(int __, int ___) : p(__), id(___) {}
};
bool visited[maxn];
int fa[maxn], lca[maxn];
vector<node> qry[maxn];
int find(int x) { // dij set
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void tarjan(int u) { // lca
visited[u] = true;
for (int v : adj[u])
if (!vis[v]) {
tarjan(v);
fa[v] = u;
}
for (node q : qry[u]) {
int x = q.p, id = q.id;
if (visited[x])
lca[id] = find(x);
}
}
struct qr{ // save the queries
int opt;
int a, b, x;
qr() = default;
qr(int o, int __, int ___) {
if (o == 3) {
opt = o;
a = __;
b = ___;
} else {
opt = o;
a = __;
x = ___;
}
}
} queries[maxn];
void solve() {
n = read();
m = read();
root = read();
for (int i = 1; i <= n; i++) cin >> v[i];
for (int i = 1; i < n; i++) {
int u = read(), v = read();
adj[u].push_back(v);
adj[v].push_back(u);
}
// build(1, 1, n);
for (int i = 1; i <= m; i++) {
int opt = read(), a = read(), b = read();
queries[i] = {opt, a, b};
if (opt == 3) {
qry[a].emplace_back(b, i);
qry[b].emplace_back(a, i);
}
}
// vis[root] = 1;
DFS(root);
tarjan(root);
for (int i = 1; i <= n; i++) // init
update_p(in[i], out[i], v[i]);
for (int i = 1; i <= m; i++) {
int o = queries[i].opt;
if (o == 3) { // chain query
int a = queries[i].a, b = queries[i].b;
int lca_node = lca[i];
sgt _ = query(in[a]), __ = query(in[b]), ___ = query(in[lca_node]);
ll ansa = _.t1 + _.t2 * (depth[dfs[a]] + 1) - _.t3;
ll ansb = __.t2 + __.t2 * (depth[dfs[b]] + 1) - __.t3;
ll ans_lca = ___.t1 + ___.t2 * (depth[dfs[lca_node]] + 1) - ___.t3;
cout << ansa + ansb - ans_lca << "\n";
} else { // other : update node a or subtree of node a
int a = queries[i].a, x = queries[i].x;
if (o == 1) update_p(in[a], out[a], x);
else if (o == 2) update_r(in[a], out[a], x);
}
}
}
int main() {
// freopen("T1.in", "r", stdin);
// freopen("T1.out", "w", stdout);
int T = 1;
while (T--) solve();
return 0;
}

浙公网安备 33010602011771号