写完裸的树练剖分后,发现似乎不用树剖,只用dfs序就可以
然后就又写了一发,样例都过不了,发现是个错的…………………………
树练剖分对于此题算是最裸的写法了
#include<set>
#include<map>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define T 111111
using namespace std;
int sc()
{
int i=0,f=1; char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
return i*f;
}
struct TREE
{
int l,r;
long long v,ch;
}tr[T*8];
int head[T],nxt[T*2],lst[T*2];
int v[T],size[T],pos[T],top[T],fa[T],s[T];
int n,m,tot,cnt;
void insert(int x,int y)
{
lst[++tot]=y; nxt[tot]=head[x]; head[x]=tot;
lst[++tot]=x; nxt[tot]=head[y]; head[y]=tot;
}
void dfs(int x,int f)
{
fa[x]=f;size[x]=1;
for(int i=head[x];i;i=nxt[i])
if(lst[i]!=f)
{
dfs(lst[i],x);
size[x]+=size[lst[i]];
}
}
void _dfs(int x,int htp)
{
top[x]=htp; pos[x]=++cnt; s[cnt]=v[x];
//cout << x <<" "<<pos[x]<<" "<<v[x]<<endl;
int k=0;
for(int i=head[x];i;i=nxt[i])
if(lst[i]!=fa[x]&&size[lst[i]]>size[k])k=lst[i];
if(!k)return ; _dfs(k,htp);
for(int i=head[x];i;i=nxt[i])
if(k!=lst[i]&&fa[x]!=lst[i])
_dfs(lst[i],lst[i]);
}
void build(int x,int l,int r)
{
tr[x].l=l;tr[x].r=r;
if(l==r)
{
tr[x].v=s[l];
return ;
}
int mid=l+r>>1;
build(x<<1,l,mid);build(x<<1|1,mid+1,r);
tr[x].v=tr[x<<1].v+tr[x<<1|1].v;
//cout << x <<" "<<tr[x].v<<endl;
}
void push_down(int x)
{
if(tr[x].ch!=0)
{
long long y=tr[x].ch;
tr[x].ch=0;
tr[x<<1].ch+=y;
tr[x<<1].v+=y*(tr[x<<1].r-tr[x<<1].l+1);
tr[x<<1|1].ch+=y;
tr[x<<1|1].v+=y*(tr[x<<1|1].r-tr[x<<1|1].l+1);
}
}
void change(int x,int l,int r,long long f)
{
push_down(x);
int L=tr[x].l,R=tr[x].r;
//cout <<L<<" "<<R<<" "<< x<<" "<<l <<" "<<r << endl;
if(L==l&&R==r)
{
tr[x].ch+=f;
tr[x].v+=f*(R-L+1);
return ;
}
int mid=L+R>>1;
if(r<=mid) change(x<<1,l,r,f);
else if(l>mid) change(x<<1|1,l,r,f);
else change(x<<1,l,mid,f),change(x<<1|1,mid+1,r,f);
tr[x].v=tr[x<<1].v+tr[x<<1|1].v;
}
long long ask(int x,int l,int r)
{
push_down(x);
int L=tr[x].l,R=tr[x].r;
if(l==L&&r==R) return tr[x].v;
int mid=L+R>>1;
if(r<=mid)return ask(x<<1,l,r);
else if(l>mid)return ask(x<<1|1,l,r);
else return ask(x<<1,l,mid)+ask(x<<1|1,mid+1,r);
}
long long solve(int x)
{
long long ans=0;
while(x)
{
int y=top[x];
ans+=ask(1,pos[y],pos[x]);
x=fa[y];
}
return ans;
}
int main()
{
n=sc();m=sc();
for(int i=1;i<=n;i++)v[i]=sc();
for(int i=1;i<n;i++)
{
int x=sc(),y=sc();
insert(x,y);
}
dfs(1,0);
_dfs(1,1);
build(1,1,cnt);
while(m--)
{
int opt=sc();
if(opt==1)
{
int y=sc(),c=sc();
change(1,pos[y],pos[y],c);
}
else if(opt==2)
{
int y=sc(),c=sc();
change(1,pos[y],pos[y]+size[y]-1,c);
}
else if(opt==3)
{
int y=sc();
printf("%lld\n",solve(y));
}
}
return 0;
}