BZOJ-4034: [HAOI2015]树上操作 线段树维护dfs出栈入栈序

[文章目录]

Description

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

没有子树移动,简单一个线段树维护出栈入栈序就好了吧。

不过这题好像是在树链剖分里的。

(弃掉zkw,开始练习结构体,毕竟有些什么区间染色,还有什么这个那个,zkw实现都很难啊。)不过练完splay之后,细节就清晰了好多。由于lazy[]没开long long WA了一次。然后就一A。开心。

结构体慢了点,但是好在如果是需要多个线段树的题目就方便多了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=101000;
typedef long long ll;
int n,m,in[N],out[N],val[N];
int head[N],to[N<<1],nxt[N<<1],cnt,tot;
int t[N<<1];
void add(int x,int y)
{
    to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; 
}
void dfs(int x,int pre)
{
    in[x]=++tot;
    t[tot]=x;
    for(int i=head[x];i;i=nxt[i])
        if(to[i]!=pre)
            dfs(to[i],x);
    out[x]=++tot;
    t[tot]=-x;
}
struct seg
{
    ll sum[N<<3],lazy[N<<3];
    int siz[N<<3];
    void pushup(int pos)
    {
        siz[pos]=siz[pos<<1]+siz[pos<<1|1];
        sum[pos]=sum[pos<<1]+sum[pos<<1|1];
    }
    void pushdown(int pos)
    {
        if(lazy[pos])
        {
            lazy[pos<<1]+=lazy[pos];
            lazy[pos<<1|1]+=lazy[pos];
            sum[pos<<1]+=1ll*lazy[pos]*siz[pos<<1];
            sum[pos<<1|1]+=1ll*lazy[pos]*siz[pos<<1|1];
            lazy[pos]=0;
        }
    }
    void build(int pos,int l,int r)
    {
        if(l==r)
        {
            siz[pos]= t[l]>0 ? 1 : -1;
            sum[pos]= t[l]>0 ? val[t[l]] : -val[-t[l]];
            return ;
        }
        int mid=l+r>>1;
        build(pos<<1,l,mid);
        build(pos<<1|1,mid+1,r);
        pushup(pos);
    }
    void fix(int pos,int l,int r,int x,int y,int w)
    {
        if(x<=l&&y>=r)
        {
            lazy[pos]+=w;
            sum[pos]+=1ll*w*siz[pos];
            return ;
        }
        pushdown(pos);
        int mid=l+r>>1;
        if(y<=mid) fix(pos<<1,l,mid,x,y,w);
        else if(x>mid) fix(pos<<1|1,mid+1,r,x,y,w);
        else fix(pos<<1,l,mid,x,y,w),fix(pos<<1|1,mid+1,r,x,y,w);
        pushup(pos);
    }
    ll query(int pos,int l,int r,int x,int y)
    {
        if(x<=l&&y>=r) return sum[pos];
        pushdown(pos);
        int mid=l+r>>1;
        if(y<=mid) return query(pos<<1,l,mid,x,y);
        else if(x>mid) return query(pos<<1|1,mid+1,r,x,y);
        else return query(pos<<1,l,mid,x,y)+query(pos<<1|1,mid+1,r,x,y);
    }
}tree;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&val[i]);
    for(int x,y,z,i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    dfs(1,0);
    tree.build(1,1,n<<1);
    int sw;
    while(m--)
    {
        scanf("%d",&sw);
        switch(sw)
        {
            case 1:
            {
                int id,w; scanf("%d%d",&id,&w);
                tree.fix(1,1,tot,in[id],in[id],w);
                tree.fix(1,1,tot,out[id],out[id],w);
                break;
            }
            case 2:
            {
                int id,w; scanf("%d%d",&id,&w);
                tree.fix(1,1,tot,in[id],out[id],w);break;
            }
            case 3:
            {
                int id; scanf("%d",&id);
                printf("%lld\n",tree.query(1,1,tot,1,in[id]));break;
            }
        }
    }
    return 0;   
}

发表评论

邮箱地址不会被公开。 必填项已用*标注