BZOJ4034 [HAOI2015]树上操作+DFS序+线段树

参考:https://www.cnblogs.com/liyinggang/p/5965981.html

题意:是一个数据结构题,树上的,用dfs序,变成线性的;

思路:对于每一个节点x,记录其DFS序,包括第一次到的序号,用in【x】记录,离开的序号out【x】记录,

再开一个数组seg,in:(序号——>节点的值);out:(序号——>节点的负值);

这样就可以使得

  对于树来说:若所求的一个区间完全包含一个不相关子树,这个子树对结果不影响;

  对于基于 线性 的线段树来说,同时包含in【x】、out【x】区间,区间求和为0;

利用线段树build 数组seg,得到区间的加和;

所以,

1-->分别更新in【x】,out【x】所对应的值;

2-->update in【x】到out【x】区间的值;

3-->返回 1 (根) 到 in【x】 区间的即可;

#include <iostream>
#include <cstdio>
#include <vector>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn = 200050;
ll sum[maxn*4];
ll seg[maxn],a[maxn],lazy[maxn*4],flag[maxn*4];
ll in[maxn],out[maxn];
ll io[maxn];
int cnt = 0;
int n,m;
vector <int> mp[maxn];
void dfs(int u,int fa)
{
    cnt++;
    seg[cnt] = 1ll*a[u],in[u] = 1ll*cnt;
    for(int i=0; i< mp[u].size(); i++)
    {
        int tmp  = mp[u][i];
        if(tmp == fa)continue;
        dfs(tmp,u);
    }
    cnt++;
    seg[cnt] = -1ll*a[u],out[u] = 1ll*cnt;  
    io[cnt] = -1;
}
void pushup(int rt)
{
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    flag[rt] = flag[rt<<1] + flag[rt<<1|1];
}
void pushdown(int rt)
{
    if(lazy[rt])
    {
        lazy[rt<<1]  += lazy[rt]; 
        lazy[rt<<1|1]+= lazy[rt];
        sum[rt<<1]   += flag[rt<<1] * lazy[rt];    
        sum[rt<<1|1] += flag[rt<<1|1]*lazy[rt];
        lazy[rt] = 0;
    }
}
void build(int rt,int l,int r)
{
    if(l==r)
    {
        sum[rt] = seg[l];
        if(io[l]==0)flag[rt] = 1;
        else flag[rt] = -1;
        return ;
    }
    int mid = (l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushup(rt);
}
    void update_one(int pos,int d,int l,int r,int rt)//单点更新;
    {
        if(l == r)
        {
            if(flag[rt] ==1 )
                sum[rt] += d;
            else sum[rt] -= d;
            return;
        }
        pushdown(rt);
        int mid = (l+r)>>1;
        if(pos<=mid) update_one(pos,d,l,mid,rt<<1);
        else update_one(pos,d,mid+1,r,rt<<1|1);
        pushup(rt);
    }
    void update_d(int L,int R,int d,int l,int r,int rt)//区间更新;
    {
        if(l >= L && R >= r)
        {
            sum[rt] += flag[rt]*d;
            lazy[rt] += d;
            return;
        }
        pushdown(rt);
        int mid = (l+r)>>1;
        if(L<=mid) update_d(L,R,d,l,mid,rt<<1);
        if(R>mid) update_d(L,R,d,mid+1,r,rt<<1|1);
        pushup(rt);
    }
    ll query(int L,int R,int l,int r,int rt)//区间查询
    {
        if(l>=L&&r<=R)
        {
            return sum[rt];
        }
        int mid = (l+r)>>1;
        ll res = 0;
        pushdown(rt);
        if(mid>=L)res += query(L,R,l,mid,rt<<1);
        if(mid<R)res +=query(L,R,mid+1,r,rt<<1|1);
        return res;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n;i++)
        {
            scanf("%lld" ,&a[i]);
        }
        
        for(int i=1; i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            mp[v].pb(u);
            mp[u].pb(v);
        }
        dfs(1,0);
        build(1,1,2*n);
        for(int i=1 ;i <= m; i++)
        {
            int op,x,val;
            scanf("%d", &op);
            if(op==1) { 
                scanf("%d%d",&x,&val);
                update_one(in[x],val,1,2*n,1);
                update_one(out[x],val,1,2*n,1);
            }
            else if(op==2) {
                scanf("%d%d",&x,&val);
                update_d(in[x],out[x],val,1,2*n,1);
            }
            else if(op==3) {    
                scanf("%d",&x);
                printf("%lld\n",query(1,in[x],1,2*n,1));
            }
        }
        return 0;
    }

 

posted @ 2018-04-28 21:24  ckxkexing  阅读(142)  评论(0编辑  收藏  举报