实现代码能力真的太差了吧 …
不能再看别人代码了 … FLAG
(搬得 zzq 的题解 … 按照我思考这个问题的顺序换了一下顺序???
如果没有平方怎么做,即要以点 p
为根,求出每个点子树的点权和,直接加在一起。
考虑一个点 s
的点权
vs
只有它及祖先才会计入,即计入了
dis(s,p)+1
次,那么没有平方的答案就是
∑ni=1dis(p,i)vi+∑ni=1vi
,这个东西显然是可以用动态点分治维护的,参见 【ZJOI 2015 幻想乡战略游戏】【动态点分治】。
现在问题就是这个平方,我们设
sx
为 x
子树的点权和,w
为点权总和,那么我们可以发现
∑ni=1si(w−si)
无论根是啥都是一个定值。
那么如果我们只要在以 1
为根的时候求出
∑ni=1siw−s2i
,然后在 p
为根时求出
∑ni=1si
,再把以 p
为根时的
∑ni=1s2i
解出来即可。
–
以 p
为根时求
∑ni=1si
只要按照幻想乡战略游戏那么求即可。
这样以 1
为根时的
∑ni=1si
我们也就可以求出来了。
w
我们也直接求得了。
那么对于以 1
为根时的
∑ni=1siw−s2i
我们只需考虑如何求以 1
为根时的
∑ni=1s2i
即可。
这是我们注意到有一个良心的 30 部分分正好是干这个的。
我们的要求就是把一个点到根的路径上的子树和全部加上一个值,询问所有点子树平方和。
考虑对一个点 x
点权 + y
对答案的贡献,我们发现对于每个 x
的父亲 f
,假设原来点权和为 p
,现在就变成了 p + y
,那么对答案贡献就是
(p+y)2−p2=2∗p∗y+y2
,我们只要统计 x
到根的点权和即可。
那么我们只要支持将一个点到根的路径点权加上一个数 y
和统计一个点到根的点权和,直接树链剖分就可以做到两个
log
。
这部分实现注意:
我们维护树剖的线段树,节点赋的初值一开始就应该是以这个节点为根的子数点权和。
每次修改操作增加的值就是 y
,另记一个变量统计每次贡献,贡献的计算:因为我们要算从 x
点到根的
∑fa[i]i=x2∗pi∗y+y2
=
2∗y∗∑fa[i]i=xpi+∑fa[i]i=xy2
注意一件事情,如果一个函数中有需要先由另一个函数求得的东西,一定要注意执行顺序。
在我们不知道是否函数的执行顺序可以随意的时候,要先注意上面所说的,否则之后调程序会很麻烦,以后调程序时要先注意一下这种错误 … 日常错误 1/1
劳资调不出来了啊 … 真的肝不动了啊 … 好气啊 … 为什么死活只能拿 30 分啊 … 改天再来补坑吧 …
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 4e5 + 5;
struct Edge {
ll to, next, w;
}e[N << 1];
ll n, q, squ = 0, total = 0;
ll a[N], sumw[N];
ll cnt = 0;
ll head[N];
void add(ll u, ll v) {
e[++ cnt].to = v; e[cnt].w = 1; e[cnt].next = head[u]; head[u] = cnt;
}
struct Chain {
ll fa[N], dep[N], hson[N], size[N];
void dfs1(ll u, ll f, ll depth) {
fa[u] = f;
dep[u] = depth;
size[u] = 1;
for (ll i = head[u]; i; i = e[i].next) {
ll v = e[i].to;
if (v == f) continue;
dfs1(v, u, depth + 1);
sumw[u] += sumw[v];
size[u] += size[v];
if (size[hson[u]] < size[v] || hson[u] == -1) hson[u] = v;
}
}
ll tim;
ll top[N], tid[N], Rank[N];
void dfs2(ll u, ll tp) {
top[u] = tp;
tid[u] = ++ tim;
Rank[tim] = u;
if (hson[u] == -1) return ;
dfs2(hson[u], tp);
for (ll i = head[u]; i; i = e[i].next) {
ll v = e[i].to;
if (v != fa[u] && v != hson[u]) dfs2(v, v);
}
}
// ----------
struct Node {
ll sum, lazy;
}tree[N << 2];
void pushup(ll i) {
tree[i].sum = tree[i << 1].sum + tree[i << 1 | 1].sum;
}
void build(ll rt, ll l, ll r) {
tree[rt].lazy = 0;
if (l == r) { tree[rt].sum = sumw[Rank[l]]; return ; }
ll mid = (l + r) >> 1;
build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
void pushdown(ll i, ll l, ll r) {
if (tree[i].lazy) {
tree[i << 1].lazy += tree[i].lazy;
tree[i << 1 | 1].lazy += tree[i].lazy;
ll mid = (l + r) >> 1;
tree[i << 1].sum += (mid - l + 1) * tree[i].lazy;
tree[i << 1 | 1].sum += (r - mid) * tree[i].lazy;
tree[i].lazy = 0;
}
}
void update(ll rt, ll l, ll r, ll ql, ll qr, ll w) {
if (ql > r || qr < l) return ;
if (ql <= l && r <= qr) {
tree[rt].lazy += w;
tree[rt].sum += (r - l + 1) * w;
return ;
}
pushdown(rt, l, r);
ll mid = (l + r) >> 1;
update(rt << 1, l, mid, ql, qr, w);
update(rt << 1 | 1, mid + 1, r, ql, qr, w);
pushup(rt);
}
ll query(ll rt, ll l, ll r, ll ql, ll qr) {
if (ql > r || qr < l) return 0;
if (ql <= l && r <= qr) return tree[rt].sum;
pushdown(rt, l, r);
ll mid = (l + r) >> 1;
return query(rt << 1, l, mid, ql, qr) + query(rt << 1| 1, mid + 1, r, ql, qr);
}
// -------------
void chainchange(ll x, ll y, ll val) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
update(1, 1, n, tid[top[x]], tid[x], val);
x = fa[top[x]];
}
if (dep[x] < dep[y]) swap(x, y);
update(1, 1, n, tid[y], tid[x], val);
}
ll chainquery(ll x, ll y) {
ll res = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
res += query(1, 1, n, tid[top[x]], tid[x]);
x = fa[top[x]];
}
if (dep[x] < dep[y]) swap(x, y);
res += query(1, 1, n, tid[y], tid[x]);
return res;
}
}chain;
struct DF_tree {
ll dffa[N], dfdep[N], dfsize[N], dfson[N], dfdis[N];
void dfs1(ll u, ll f, ll depth) {
dffa[u] = f;
dfdep[u] = depth;
dfsize[u] = 1;
for(ll i = head[u]; i; i = e[i].next) {
ll v = e[i].to;
if(v != dffa[u]) {
dfs1(v, u, depth + 1);
dfdis[v] = dfdis[u] + e[i].w;
dfsize[u] += dfsize[v];
if (dfson[u] == -1 || dfsize[dfson[u]] < dfsize[v])
dfson[u] = v;
}
}
}
ll top[N];
void dfs2(ll u, ll tp) {
top[u] = tp;
if (dfson[u] == - 1) return ;
dfs2(dfson[u], tp);
for(ll i = head[u]; i; i = e[i].next) {
ll v = e[i].to;
if(v != dffa[u] && v != dfson[u])
dfs2(v, v);
}
}
ll lca(ll a, ll b) {
while (top[a] != top[b]) {
if (dfdep[top[a]] > dfdep[top[b]]) a = dffa[top[a]];
else b = dffa[top[b]];
}
return (dfdep[a] < dfdep[b]) ? a : b;
}
ll getdis(ll x, ll y) {
return (dfdis[x] + dfdis[y]) - 2 * dfdis[lca(x, y)];
}
// ----------
ll rt, sum;
ll size[N], son[N], vis[N];
void getrt(ll u, ll f) {
son[u] = 1;
size[u] = 0;
for (ll i = head[u]; i; i = e[i].next) {
ll v = e[i].to;
if (v == f || vis[v]) continue;
getrt(v, u);
son[u] += son[v];
size[u] = max(size[u], son[v]);
}
size[u] = max(size[u], sum - son[u]);
if (size[u] < size[rt]) rt = u;
}
void getsize(ll u, ll f) {
son[u] = 1;
for (ll i = head[u]; i; i = e[i].next) {
ll v = e[i].to;
if (vis[v] || v == f) continue;
getrt(v, u);
son[u] += son[v];
}
}
ll fa[N];
void solve(ll u, ll f) {
vis[u] = 1; fa[u] = f;
for (ll i = head[u]; i; i = e[i].next) {
ll v = e[i].to;
if (vis[v]) continue;
getsize(v, 0);
sum = size[0] = son[v];
getrt(v, rt = 0);
solve(rt, u);
}
}
ll cost[N], costfa[N]; // 子树代价和
ll dfsum[N], dfsumfa[N]; // 子树权值和
void pre() {
for (ll u = 1; u <= n; u ++) {
dfsum[u] += a[u];
for (ll i = u; fa[i]; i = fa[i]) {
ll disnum = getdis(u, fa[i]);
dfsum[fa[i]] += a[u];
dfsumfa[i] += a[u];
cost[fa[i]] += disnum * a[u];
costfa[i] += disnum * a[u];
}
}
}
ll cal(ll u) {
int ans = cost[u];
for (ll i = u; fa[i]; i = fa[i]) {
ll disnum = getdis(u, fa[i]);
ans += cost[fa[i]] - costfa[i];
ans += disnum * (dfsum[fa[i]] - dfsumfa[i]);
}
return ans + total;
}
void dftreechange(ll u, ll val) {
dfsum[u] += val;
for (ll i = u; fa[i]; i = fa[i]) {
ll disnum = getdis(u, fa[i]);
dfsum[fa[i]] += val;
dfsumfa[i] += val;
cost[fa[i]] += disnum * val;
costfa[i] += disnum * val;
}
}
}dftree;
int main() {
//freopen("1.in", "r", stdin);
memset(chain.hson, -1, sizeof(chain.hson));
memset(dftree.dfson, -1, sizeof(dftree.dfson));
memset(dftree.vis, 0, sizeof(dftree.vis));
memset(dftree.dfdis, 0, sizeof(dftree.dfdis));
chain.tim = 0;
scanf("%lld%lld", &n, &q);
for (ll i = 1; i < n; i ++) {
ll x, y;
scanf("%lld%lld", &x, &y);
add(x, y), add(y, x);
}
for (ll i = 1; i <= n; i ++) scanf("%lld", &a[i]), sumw[i] = a[i], total += a[i];
dftree.sum = dftree.size[0] = n;
dftree.getrt(1, dftree.rt = 0);
ll oldrt = dftree.rt;
dftree.solve(dftree.rt, 0);
dftree.dfs1(oldrt, 0, 0); dftree.dfs2(oldrt, oldrt);
dftree.pre();
chain.dfs1(1, 0, 0); chain.dfs2(1, 1);
chain.build(1, 1, n);
for (ll i = 1; i <= n; i ++) squ += sumw[i] * sumw[i];
for (ll i = 1; i <= q; i ++) {
ll o;
scanf("%lld", &o);
if (o == 1) {
ll x, y;
scanf("%lld%lld", &x, &y);
ll addvar = y - a[x];
total += addvar;
a[x] = y;
ll old = chain.chainquery(1, x);
squ += ((old * addvar) << 1) + addvar * addvar * (chain.dep[x] + 1);
chain.chainchange(1, x, addvar);
dftree.dftreechange(x, addvar);
}
else if (o == 2) {
ll u;
scanf("%lld", &u);
ll lst = dftree.cal(1) * total - squ;
ll ans = dftree.cal(u) * total - lst;
printf("%lld\n", ans);
}
}
return 0;
}