传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4034
题解:树上单点修改+子树修改+链查询
单点修改和链的查询都属于裸的树链剖分,比较好想,那么剩下的就是子树修改的部分。
因为每个点的子树的范围在线段树上表示的是从这个点到它的子树的最后一个点,那么对于每个点在深搜的时候记录一下它的子树的最后一个点即可,修改的时候直接在线段树上做区间修改就搞定了,具体的过程还是看代码吧。
这道题一定要开long long!!!
本来算一下感觉int可以卡过去的,之后就被虐成渣了!
Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100010
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long ll;
struct ss
{
int next,to;
};
ss Edge[N<<1];
int n,m,tot,s;
ll f[N<<2];
int a[N];
int w[N];
int fa[N];
int zz[N];
int dfn[N];
int son[N];
int top[N];
ll sum[N<<2];
int size[N];
int head[N];
int pp[N];
void addedge(int x,int y)
{
Edge[++tot].next=head[x];
Edge[tot].to=y;
head[x]=tot;
}
void dfs1(int u,int root,int deep)
{
dfn[u]=deep;
fa[u]=root;
size[u]=1;
for(int i=head[u];i;i=Edge[i].next)
{
int to=Edge[i].to;
if(to==root)continue;
dfs1(to,u,deep+1);
size[u]+=size[to];
if(size[son[u]]<size[to])son[u]=to;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
w[u]=++s;
pp[s]=u;
if(!son[u])
{
zz[u]=w[u];
return ;
}
dfs2(son[u],tp);
zz[u]=zz[son[u]];
for(int i=head[u];i;i=Edge[i].next)
{
int to=Edge[i].to;
if(to==fa[u]||to==son[u])continue;
dfs2(to,to);
zz[u]=max(zz[u],zz[to]);
}
}
void PushUp(int rt)
{
f[rt]=f[ls]+f[rs];
}
void PushDown(int l,int r,int rt)
{
if(!sum[rt])return ;
int mid=(l+r)>>1;
sum[ls]+=sum[rt],sum[rs]+=sum[rt];
f[ls]+=sum[rt]*(ll)(mid-l+1);
f[rs]+=sum[rt]*(ll)(r-mid);
sum[rt]=0;
}
void build(int l,int r,int rt)
{
sum[rt]=0;
if(l==r)
{
f[rt]=a[pp[l]];
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
PushUp(rt);
}
void updata(int l,int r,int rt,int L,int R,int c)
{
if(l>=L&&r<=R)
{
f[rt]+=(ll)c*(ll)(r-l+1);
sum[rt]+=(ll)c;
return ;
}
PushDown(l,r,rt);
int mid=(l+r)>>1;
if(mid>=L)updata(lson,L,R,c);
if(mid<R) updata(rson,L,R,c);
PushUp(rt);
}
ll ask(int l,int r,int rt,int L,int R)
{
if(l>=L&&r<=R)return f[rt];
PushDown(l,r,rt);
int mid=(l+r)>>1;
ll ans=0;
if(mid>=L)ans+=ask(lson,L,R);
if(mid<R)ans+=ask(rson,L,R);
return ans;
}
ll query(int x)
{
ll cnt=0;
while(x!=0)
{
cnt+=ask(1,n,1,w[top[x]],w[x]);
x=fa[top[x]];
}
return cnt;
}
int main()
{
cin>>n>>m;
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);
addedge(x,y),addedge(y,x);
}
dfs1(1,0,1);
dfs2(1,1);
build(1,n,1);
for(int i=1;i<=m;i++)
{
int opt,x,y;
scanf("%d",&opt);
switch(opt)
{
case 1: scanf("%d%d",&x,&y);
updata(1,n,1,w[x],w[x],y);
break;
case 2: scanf("%d%d",&x,&y);
updata(1,n,1,w[x],zz[x],y);
break;
case 3: scanf("%d",&x);
printf("%lld\n",query(x));
break;
}
}
return 0;
}