背景
大家好,我是一名勇敢的俄罗斯士兵,我昨天正在打 C o d e F o r c e s \tt CodeForces CodeForces 呢,突然被拉去打仗了。我们已经突入基辅,但因为推进过于迅速,后勤补给未能补上,我们现在急需
143 元来购买一些吃的一个能替代通信员的老兄来解密一下临时截获的乌克兰电报,密钥似乎是一道信息题。等我们打赢了,就分你一个 【 数 据 删 除 】 _{^{【数据删除】}} 【数据删除】 作为答谢。不说了又要冲锋了,乌拉!!!
题面
给定一棵以 1 1 1 为根的有根树, i i i 号点有点权 v i v_i vi。接下来你需要对其进行 q q q 次操作,操作有 3 3 3 种:
-
S u d
: v u ← v u + d v_u ← v_u + d vu←vu+d; -
M u d
:对于 u u u 子树中的任意一点 x x x(包括 u u u), v x ← v x + d v_x ← v_x + d vx←vx+d; -
Q u
:求 ∑ i = 1 n ∑ j = i + 1 n [ L C A ( i , j ) = u ] v i v j m o d 2 63 ∑^n_{i=1}∑_{j=i+1}^n[LCA(i, j) = u]v_iv_j \mod 2^{63} ∑i=1n∑j=i+1n[LCA(i,j)=u]vivjmod263。
2 ≤ n , q ≤ 2 × 1 0 5 , 1 ≤ f i ≤ i , 0 ≤ d , v i ≤ 1 0 9 2 ≤ n, q ≤ 2 × 10^5, 1 ≤ f_i ≤ i, 0 ≤ d, v_i ≤ 10^9 2≤n,q≤2×105,1≤fi≤i,0≤d,vi≤109 。
题解
令 a n s ( u ) = ∑ i = 1 n ∑ j = i + 1 n [ L C A ( i , j ) = u ] v i v j m o d 2 63 ans(u)=∑^n_{i=1}∑_{j=i+1}^n[LCA(i, j) = u]v_iv_j \mod 2^{63} ans(u)=∑i=1n∑j=i+1n[LCA(i,j)=u]vivjmod263 (其实就是把它简写了一下), f ( u ) = ∑ i = 1 n ∑ j = 1 n [ L C A ( i , j ) = u ] v i v j m o d 2 64 = 2 a n s ( u ) + v u 2 f(u)=∑^n_{i=1}∑_{j=1}^n[LCA(i, j) = u]v_iv_j \mod 2^{64}=2ans(u)+v_u^2 f(u)=∑i=1n∑j=1n[LCA(i,j)=u]vivjmod264=2ans(u)+vu2,我们很容易想到用重链剖分维护每个点的 f ( u ) f(u) f(u) 。
设 s v ( u ) sv(u) sv(u) 表示 u u u 的子树点权和,那么 f ( u ) = s v ( u ) 2 − ∑ i ∈ s o n u s v ( i ) 2 f(u)=sv(u)^2-\sum_{i\in son_u}sv(i)^2 f(u)=sv(u)2−∑i∈sonusv(i)2(和点分治的容斥是一个原理),我们暴力维护每个点轻儿子的 s v ( i ) 2 sv(i)^2 sv(i)2 和,记为 s m 2 ( u ) sm^2(u) sm2(u)。
但是子树修改权值将十分麻烦,子树中所有的信息都会变化,包括 s m 2 ( u ) sm^2(u) sm2(u) 。所以我们不妨将子树修改的懒标记永久化,子树维护的所有值都排除祖先的懒标记的影响。在求答案的时候再考虑懒标记总和 d d d 会带来什么影响。
由于 ( v i + d ) ( v j + d ) = v i v j + d ( v i + v j ) + d 2 (v_i+d)(v_j+d)=v_iv_j+d(v_i+v_j)+d^2 (vi+d)(vj+d)=vivj+d(vi+vj)+d2 ,所以我们还要维护 ∑ i = 1 n ∑ j = 1 n [ L C A ( i , j ) = u ] ( v i + v j ) m o d 2 64 ∑^n_{i=1}∑_{j=1}^n[LCA(i, j) = u](v_i+v_j) \mod 2^{64} ∑i=1n∑j=1n[LCA(i,j)=u](vi+vj)mod264 和 ∑ i = 1 n ∑ j = 1 n [ L C A ( i , j ) = u ] m o d 2 64 ∑^n_{i=1}∑_{j=1}^n[LCA(i, j) = u] \mod 2^{64} ∑i=1n∑j=1n[LCA(i,j)=u]mod264 ,两者都能和 f ( u ) f(u) f(u) 相似地维护。
最后算答案的时候细节极多。
时间复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n) 。
CODE
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
//#define getchar() xchar()
LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
int n,m,s,o,k;
int hd[MAXN],nx[MAXN],v[MAXN],cne;
void ins(int x,int y) {
nx[++ cne] = hd[x]; v[cne] = y; hd[x] = cne;
}
ULL tre[MAXN<<2],lz[MAXN<<2];
int M;
void maketree(int n) {M=1;while(M<n+2)M<<=1;}
void addp(int x,ULL y) {
for(int s=M+x;s;s>>=1)tre[s]+=y;
}
void addtree(int l,int r,ULL y) {
if(l > r) return ;
int le = 1;
for(int s = M+l-1,t = M+r+1;s || t;s >>= 1,t >>= 1,le <<= 1) {
if(s<M) tre[s] = tre[s<<1]+tre[s<<1|1]+lz[s]*le;
if(t<M) tre[t] = tre[t<<1]+tre[t<<1|1]+lz[t]*le;
if((s>>1) != (t>>1)) {
if(!(s&1)) tre[s^1] += y*le,lz[s^1] += y;
if(t & 1) tre[t^1] += y*le,lz[t^1] += y;
}
}return ;
}
ULL findplz(int x) {
int s = M+x;ULL as = 0;
while(s) as += lz[s],s >>= 1;
return as;
}
ULL findtree(int l,int r) {
if(l > r || !l || !r) return 0ull;
ULL as = 0; int ls = 0,rs = 0,le = 1;
for(int s = M+l-1,t = M+r+1;s || t;s >>= 1,t >>= 1,le <<= 1) {
as += lz[s]*ls + lz[t]*rs;
if((s>>1) != (t>>1)) {
if(!(s&1)) as += tre[s^1],ls += le;
if(t & 1) as += tre[t^1],rs += le;
}
}return as;
}
ULL dp3[MAXN],sm2[MAXN],sm1[MAXN];
int d[MAXN],fa[MAXN],siz[MAXN],son[MAXN];
int tp[MAXN],dfn[MAXN],rr[MAXN],id[MAXN],tim;
void dfs1(int x,int ff) {
d[x] = d[fa[x] = ff] + 1;
siz[x] = 1; son[x] = 0; dp3[x] = 1;
for(int i = hd[x];i;i = nx[i]) {
dfs1(v[i],x);
dp3[x] += siz[x] *2ll* siz[v[i]];
siz[x] += siz[v[i]];
if(siz[v[i]] > siz[son[x]]) son[x] = v[i];
}
return ;
}
void dfs2(int x,int ff) {
if(son[ff] == x) tp[x] = tp[ff];
else tp[x] = x;
dfn[x] = ++ tim; id[tim] = x;
if(son[x]) dfs2(son[x],x);
for(int i = hd[x];i;i = nx[i]) {
if(v[i] != son[x]) {
dfs2(v[i],x);
}
}
rr[x] = tim;
return ;
}
void addt(int x,ULL y) {
addtree(dfn[x],rr[x],y);
ULL adn = siz[x]*y;
x = tp[x];
while(fa[x]) {
int p = fa[x];
ULL ssm = findtree(dfn[x],rr[x]) - findplz(dfn[p])*siz[x] - adn;
sm2[p] += adn*ssm*2 + adn*adn;
sm1[p] += adn*siz[x];
x = tp[p];
}return ;
}
void addsingle(int x,ULL y) {
addp(dfn[x],y);
x = tp[x];
while(fa[x]) {
int p = fa[x];
ULL ssm = findtree(dfn[x],rr[x]) - findplz(dfn[p])*siz[x] - y;
sm2[p] += y*ssm*2 + y*y;
sm1[p] += y*siz[x];
x = tp[p];
}return ;
}
ULL query(int x) {
ULL flz = findplz(dfn[x]),me = findtree(dfn[x],dfn[x]);
ULL smh = findtree(dfn[son[x]],rr[son[x]]) - flz*siz[son[x]],sm = findtree(dfn[x],rr[x]) - flz*siz[x];
ULL s1 = sm*siz[x] - sm1[x] - smh*siz[son[x]],s2 = sm*sm - sm2[x] - smh*smh;
return s2 + flz*s1*2 + flz*flz*dp3[x] - me*me;
}
int main() {
freopen("ancestor.in","r",stdin);
freopen("ancestor.out","w",stdout);
n = read();int Q = read();
for(int i = 2;i <= n;i ++) {
s = read(); ins(s,i);
}
dfs1(1,0); dfs2(1,0);
maketree(n);
for(int i = 1;i <= n;i ++) {
addp(dfn[i],read());
}
for(int i = 1;i <= n;i ++) {
for(int j = hd[i];j;j = nx[j]) {
if(v[j] != son[i]) {
ULL fd = findtree(dfn[v[j]],rr[v[j]]);
sm2[i] += fd*fd; sm1[i] += fd*siz[v[j]];
}
}
}
while(Q --) {
char c = getchar();
while(c == ' ' || c == '\n') c = getchar();
if(c == 'S') {
s = read();k = read();
addsingle(s,k);
}
else if(c == 'M') {
s = read();k = read();
addt(s,k);
}
else {
AIput(query(read())>>1,'\n');
}
}
return 0;
}