[HAOI2015]树上操作
题目:BZOJ4034、洛谷P3178。
题目大意:有一棵点数为 N 的树,以点 1 为根,且树有点权。然后有 M 个操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
现在要你输出所有询问的答案。
解题思路:对树上的节点修改查询,很容易想到树链剖分。
单点修改就相当于只包含一个节点的区间修改。
子树修改,由于树链剖分中一棵子树的dfs序连续,相当于区间修改。
查询就相当于多次区间查询。
树链剖分时间复杂度$O(n\log^2 n)$。
C++ Code:
#include<cstdio>
#include<cctype>
#include<cstring>
#define N 100005
#define mem(a) memset(&a,0,sizeof a)
#define ll long long
int n,m,a[N],aa[N],dfn[N],idx,cnt,head[N],sz[N],fa[N],top[N],son[N],dep[N];
ll ans;
struct edge{
int to,nxt;
}e[N<<1];
struct SegmentTreeNode{
ll s,add;
}d[N<<2];
inline int readint(){
char c=getchar();
bool b=false;
for(;!isdigit(c);c=getchar())b=c=='-';
int d=0;
for(;isdigit(c);c=getchar())
d=(d<<3)+(d<<1)+(c^'0');
return b?-d:d;
}
void dfs(int now){
sz[now]=1;
for(int i=head[now];i;i=e[i].nxt)
if(!dep[e[i].to]){
dep[e[i].to]=dep[now]+1;
fa[e[i].to]=now;
dfs(e[i].to);
sz[now]+=sz[e[i].to];
if(!son[now]||sz[e[i].to]>sz[son[now]])
son[now]=e[i].to;
}
}
void dfs2(int now){
dfn[now]=++idx;
if(son[now])top[son[now]]=top[now],dfs2(son[now]);
for(int i=head[now];i;i=e[i].nxt)
if(dep[e[i].to]>dep[now]&&e[i].to!=son[now])
top[e[i].to]=e[i].to,dfs2(e[i].to);
}
inline void pushdown(int len,int o){
int l=o<<1,r=o<<1|1;
d[l].add+=d[o].add;
d[r].add+=d[o].add;
d[l].s+=d[o].add*((len+1)>>1);
d[r].s+=d[o].add*(len>>1);
d[o].add=0;
}
void build(int l,int r,int o){
if(l==r){
d[o].s=aa[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,o<<1);
build(mid+1,r,o<<1|1);
d[o].s=d[o<<1].s+d[o<<1|1].s;
}
void add(int l,int r,int o,int L,int R,int k){
if(L<=l&&r<=R){
d[o].add+=k;
d[o].s+=(ll)k*(r-l+1);
return;
}
pushdown(r-l+1,o);
int mid=(l+r)>>1;
if(L<=mid)add(l,mid,o<<1,L,R,k);
if(mid<R)add(mid+1,r,o<<1|1,L,R,k);
d[o].s=d[o<<1].s+d[o<<1|1].s;
}
void query(int l,int r,int o,int L,int R){
if(L<=l&&r<=R){
ans+=d[o].s;
return;
}
pushdown(r-l+1,o);
int mid=(l+r)>>1;
if(L<=mid)query(l,mid,o<<1,L,R);
if(mid<R)query(mid+1,r,o<<1|1,L,R);
}
void que(int x){
while(top[x]!=1){
query(1,n,1,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
query(1,n,1,dfn[1],dfn[x]);
}
int main(){
idx=cnt=0;
n=readint(),m=readint();
mem(dfn);mem(head);mem(sz);mem(fa);mem(top);mem(son);mem(dep);mem(d);
for(int i=1;i<=n;++i)a[i]=readint();
for(int i=1;i<n;++i){
int u=readint(),v=readint();
e[++cnt]=(edge){v,head[u]};
head[u]=cnt;
e[++cnt]=(edge){u,head[v]};
head[v]=cnt;
}
fa[1]=top[1]=dep[1]=1;
dfs(1);dfs2(1);
for(int i=1;i<=n;++i)aa[dfn[i]]=a[i];
build(1,n,1);
while(m--){
int f=readint();
if(f==1){
int x=readint(),k=readint();
add(1,n,1,dfn[x],dfn[x],k);
}else
if(f==2){
int x=readint(),k=readint();
add(1,n,1,dfn[x],dfn[x]+sz[x]-1,k);
}else{
int x=readint();
ans=0;
que(x);
printf("%lld\n",ans);
}
}
return 0;
}

浙公网安备 33010602011771号