4034: [HAOI2015]树上操作
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 7160 Solved: 2435
[Submit][Status][Discuss]
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
思路:
扫描二维码关注公众号,回复:
2669962 查看本文章
dfs序维护一个子树的区间,求节点到根的和时用树链剖分处理。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+10;
int n,Q,tol,a[maxn];
int seg[maxn],rev[maxn],size[maxn],son[maxn],dep[maxn];
int fa[maxn],top[maxn],LL[maxn],RR[maxn];
int head[maxn];
ll sum[maxn<<2],add[maxn<<2];
struct node
{
int to,next;
}rode[maxn*2];
void add_edge(int a,int b)
{
rode[tol].to=b;
rode[tol].next=head[a];
head[a]=tol++;
}
void dfs1(int v,int father)
{
size[v]=1;
dep[v]=dep[father]+1;
fa[v]=father;
for(int i=head[v];i!=-1;i=rode[i].next)
{
node e=rode[i];
if(e.to==father) continue;
dfs1(e.to,v);
size[v]+=size[e.to];
if(size[son[v]]<size[e.to]) son[v]=e.to;
}
}
void dfs2(int v,int father)
{
LL[v]=seg[0];
if(son[v])
{
seg[son[v]]=++seg[0];
rev[seg[0]]=son[v];
top[son[v]]=top[v];
dfs2(son[v],v);
}
for(int i=head[v];i!=-1;i=rode[i].next)
{
node e=rode[i];
if(!top[e.to])
{
seg[e.to]=++seg[0];
rev[seg[0]]=e.to;
top[e.to]=e.to;
dfs2(e.to,v);
}
}
RR[v]=seg[0];
}
void build(int l,int r,int rt)
{
add[rt]=0;
if(l==r)
{
sum[rt]=a[rev[l]];
return;
}
int mid=(l+r)/2;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void push_down(int l,int r,int rt)
{
if(add[rt])
{
int mid=(l+r)/2;
sum[rt<<1]+=add[rt]*(mid-l+1);
sum[rt<<1|1]+=add[rt]*(r-mid);
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
add[rt]=0;
}
}
void update(int L,int R,int C,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
add[rt]+=C;
sum[rt]=sum[rt]+1LL*C*1LL*(r-l+1);
return;
}
push_down(l,r,rt);
int mid=(l+r)/2;
if(L<=mid) update(L,R,C,l,mid,rt<<1);
if(R>mid) update(L,R,C,mid+1,r,rt<<1|1);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
ll query(int L,int R,int l,int r,int rt)
{
if(l>=L&&r<=R) return sum[rt];
push_down(l,r,rt);
int mid=(l+r)/2;
ll ans=0;
if(L<=mid) ans+=query(L,R,l,mid,rt<<1);
if(R>mid) ans+=query(L,R,mid+1,r,rt<<1|1);
return ans;
}
ll work(int x)
{
ll ans=0;
int fx=top[x];
while(fx!=1)
{
ans+=query(seg[fx],seg[x],1,seg[0],1);
x=fa[fx];fx=top[x];
}
return ans+query(seg[fx],seg[x],1,seg[0],1);
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++)
{
int x,y;scanf("%d%d",&x,&y);
add_edge(x,y);add_edge(y,x);
}
dfs1(1,0);
seg[0]=seg[1]=rev[1]=top[1]=LL[1]=1;
dfs2(1,0);
build(1,n,1);
while(Q--)
{
int op,x,y; scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&x,&y);
update(seg[x],seg[x],y,1,seg[0],1);
}
else if(op==2)
{
scanf("%d%d",&x,&y);
update(LL[x],RR[x],y,1,seg[0],1);
}
else
{
scanf("%d",&x);
printf("%lld\n",work(x));
}
}
return 0;
}