题意
内存限制:256 MiB
时间限制:2000 ms
圣诞节来了,仓鼠又要来策划活动了,今年仓鼠会在圣诞树上挂上铃铛!
已知圣诞树有
n
n
n 个节点,并且根节点是固定的。记
s
[
i
]
s[i]
s[i] 表示以
i
i
i 为根的子树中,所有节点上铃铛数目的总和。但仓鼠觉得询问
s
[
i
]
s[i]
s[i] 太简单了,他决定给定
l
l
l 和
r
r
r,要你回答
∑
i
=
l
r
s
[
i
]
\sum\limits_{i=l}^{r}s[i]
i=l∑rs[i] 的值。
但是为了避免有的人一次预处理后一劳永逸,仓鼠在大家答题的过程中还会修改某个节点上灯笼的数量。仓鼠还要去筹备活动,你能帮助他写一个程序帮助实时给出标准答案吗?
n
,
q
≤
100000
n,q \leq 100000
n,q≤100000
题解
①考虑对原编号分块,
记
f
i
,
j
f_{i,j}
fi,j 表示
i
i
i 点对
j
j
j 块所造成的贡献,
s
j
s_j
sj 表示
j
j
j 这一块的答案
1)考虑修改
假设在
x
x
x 点上加上
v
v
v ,那就利用
f
f
f 数组进行对每个
s
j
s_j
sj 进行修改
2)考虑查询
设查询
[
l
,
r
]
[l,r]
[l,r] ,设
b
l
b_l
bl 为
l
l
l 在的块
那对于
[
b
l
+
1
,
b
r
−
1
]
[b_l+1,b_r-1]
[bl+1,br−1] 的块可以累加
s
s
s
对于剩下的,我们需要每个点
O
(
1
)
O(1)
O(1) 求出答案
②对
d
f
s
dfs
dfs 序进行分块
设
s
u
m
i
sum_i
sumi 表示
d
f
s
dfs
dfs 序不小于
i
i
i 的点的权值和
t
a
g
j
tag_j
tagj 表示这个块的后缀和都要加上的值
对于修改,我们只需要暴力修改
x
x
x 的块的每个
s
u
m
x
sum_x
sumx ,然后再把
[
1
,
b
x
−
1
]
[1,b_x-1]
[1,bx−1] 的块的
t
a
g
tag
tag 加上
v
v
v
回到原来的问题,每个点对应着一段
d
f
s
dfs
dfs 序
[
l
,
r
]
[l,r]
[l,r] ,所以它的答案就是
s
u
m
l
+
t
a
g
b
l
−
s
u
m
r
+
1
−
t
a
g
b
r
+
1
sum_l+tag_{b_l}-sum_{r+1}-tag_{b_{r+1}}
suml+tagbl−sumr+1−tagbr+1
效率
O
(
n
×
s
q
r
t
(
n
)
)
O(n \times sqrt(n))
O(n×sqrt(n))
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=100005,M=350;
int w[N],n,q,rt,hd[N],V[N*2],nx[N*2],c[M];
int f[N][M],t,tt,B,b[N],Z,in[N],ot[N];
LL sum[N],tg[M],s[M],A,sz[N];
void add(int u,int v){
V[++t]=v;nx[t]=hd[u];hd[u]=t;
}
void dfs(int x,int fa){
sum[in[x]=++tt]=sz[x]=w[x];f[x][b[x]]++;
for (int i=hd[x];i;i=nx[i])
if (V[i]!=fa){
for (int j=1;j<=Z;j++)
f[V[i]][j]=f[x][j];
dfs(V[i],x),sz[x]+=sz[V[i]];
}
ot[x]=tt;s[b[x]]+=sz[x];
}
int main(){
scanf("%d%d",&n,&q);B=sqrt(n);
for (int i=1;i<=n;i++){
scanf("%d",&w[i]),b[i]=(i-1)/B+1;
if (b[i]!=b[i-1]) c[b[i-1]]=i-1;
}
for (int x,y,i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if (!x) rt=y;else add(x,y),add(y,x);
}
c[Z=b[n]]=n;dfs(rt,0);
for (int i=n;i;i--) sum[i]+=sum[i+1];
for (int op,l,r,j;q--;){
scanf("%d%d%d",&op,&l,&r);
if (op&1){
A=r-w[l];w[l]=r;for (j=1;j<=Z;j++)
s[j]+=A*f[l][j];l=in[l];
for (j=l;b[j]==b[l];j--) sum[j]+=A;
for (j=b[j];j;j--) tg[j]+=A;continue;
}
A=0;for (j=b[l]+1;j<b[r];j++) A+=s[j];
for (j=l;j<=c[b[l]] && j<=r;j++)
A+=sum[in[j]]+tg[b[in[j]]]-sum[ot[j]+1]-tg[b[ot[j]+1]];
if (b[l]<b[r])
for (j=c[b[r]-1]+1;j<=r;j++)
A+=sum[in[j]]+tg[b[in[j]]]-sum[ot[j]+1]-tg[b[ot[j]+1]];
printf("%lld\n",A);
}
return 0;
}