题目链接
给出一棵 n n n 个点的树,每个点有点权。给出 q q q 个操作,有 4 4 4 种操作:
树链剖分把树上问题转化为序列上的问题, 3 3 3 修改种操作使用 2 2 2 个标记就可以实现,都是 × x + y \times x + y ×x+y 的形式
所以维护和,平方和,立方和,乘法标记和加法标记即可。
#include
#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;
}