BZOJ 4034 T2 (树链剖分解决子树问题)

来源:互联网 发布:python datetime 编辑:程序博客网 时间:2024/06/06 03:26

树链剖分有这样一个性质,即在剖完之后每个结点下面子树的编号一定是连续的,那么基于这一点,我们记录每个结点的区间就能解决子树更新问题

dfs序也可以解决子树问题,但是这里需要计算一个贡献值,结点的层数不好处理。


#include<cstring>#include<iostream>#include<algorithm>#include<cstdio>using namespace std;#define maxn 200004int fir[maxn],nex[maxn],v[maxn],e_max;int in[maxn],out[maxn],son[maxn],fa[maxn],siz[maxn],deep[maxn],top[maxn],tot;long long val[maxn],val1[maxn],sum[2*maxn],tag[2*maxn];void init_(){    memset(fir,-1,sizeof fir);    memset(son,-1,sizeof son);    e_max=0;    tot=1;}void add_edge(int s,int t){    int e=e_max++;    v[e]=t;    nex[e]=fir[s];    fir[s]=e;}void dfs1(int k,int pre,int d){    deep[k]=d;    fa[k]=pre;    siz[k]=1;    for(int i=fir[k];~i;i=nex[i])    {        int e=v[i];        if(e!=pre)        {            dfs1(e,k,d+1);            siz[k]+=siz[e];            if(son[k]==-1||siz[son[k]]<siz[e]) son[k]=e;        }    }}void dfs2(int k,int sp){    top[k]=sp;    in[k]=tot++;    out[k]=in[k];    val1[in[k]]=val[k];    if(son[k]==-1) return;    dfs2(son[k],sp);    out[k]=max(out[k],out[son[k]]);    for(int i=fir[k];~i;i=nex[i])    {        int e=v[i];        if(e!=fa[k]&&e!=son[k])        {            dfs2(e,e);            out[k]=max(out[k],out[e]);        }    }}void init(int l,int r,int k){    tag[k]=0;    if(l==r)    {        sum[k]=val1[l];        return ;    }    int mid=l+r>>1;    init(l,mid,k<<1);    init(mid+1,r,k<<1|1);    sum[k]=sum[k<<1]+sum[k<<1|1];}void pushdown(int k,int l,int r){    if(!tag[k]) return ;    int mid=l+r>>1;    tag[k<<1]+=tag[k];    tag[k<<1|1]+=tag[k];    sum[k<<1]+=(mid-l+1)*tag[k];    sum[k<<1|1]+=(r-mid)*tag[k];    tag[k]=0;}void update(int val,int s,int t,int l,int r,int k){    if(s==l&&r==t)    {        tag[k]+=val;        sum[k]+=(long long)(r-l+1)*val;        return ;    }    pushdown(k,l,r);    int mid=l+r>>1;    if(t<=mid) update(val,s,t,l,mid,k<<1);    else if(s>mid) update(val,s,t,mid+1,r,k<<1|1);    else update(val,s,mid,l,mid,k<<1),update(val,mid+1,t,mid+1,r,k<<1|1);    sum[k]=sum[k<<1]+sum[k<<1|1];}long long query(int s,int t,int l,int r,int k){    if(s==l&&r==t)    {        return sum[k];    }    pushdown(k,l,r);    int mid=l+r>>1;    if(t<=mid) return query(s,t,l,mid,k<<1);    else if(s>mid) return query(s,t,mid+1,r,k<<1|1);    else return query(s,mid,l,mid,k<<1)+query(mid+1,t,mid+1,r,k<<1|1);}long long Query(int s,int t){    long long sum=0;    int f1=top[s],f2=top[t];    while(f1!=f2)    {        if(deep[f1]<deep[f2]) swap(f1,f2),swap(s,t);        sum+=query(in[f1],in[s],1,tot-1,1);        s=fa[f1];        f1=top[s];    }    if(deep[s]>deep[t]) swap(s,t);    sum+=query(in[s],in[t],1,tot-1,1);    return sum;}int main(){    int n,m;    while(scanf("%d%d",&n,&m)!=EOF)    {        init_();        for(int i=1;i<=n;i++) scanf("%lld",&val[i]);        for(int i=1;i<n;i++)        {            int a,b;            scanf("%d%d",&a,&b);            add_edge(a,b);            add_edge(b,a);        }        dfs1(1,-1,1);        dfs2(1,1);        init(1,tot-1,1);       // for(int i=1;i<=n;i++) cout<<i<<' '<<in[i]<<' '<<out[i]<<' '<<val1[in[i]]<<endl;        while(m--)        {            int op;            scanf("%d",&op);            if(op==1)            {                int x,val;                scanf("%d%d",&x,&val);                update(val,in[x],in[x],1,tot-1,1);            }            else if(op==2)            {                int x,val;                scanf("%d%d",&x,&val);                update(val,in[x],out[x],1,tot-1,1);            }            else            {                int x;                scanf("%d",&x);                long long ans=Query(1,x);                printf("%lld\n",ans);            }        }    }    return 0;}


0 0