BZOJ 4034 线段树+DFS序

思路:
先搞出来每个点的DFS序 (要有入栈和出栈两种状态的)
处理出来 线段树区间有多少入栈的和多少出栈的

加区间的时候就加(入-出)*wei

查前缀和

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 200050
#define int long long
int n,m,Wei[N],v[N],first[N],next[N],tot,start[N],end[N],cnt;
int xx,yy,ww,op,tree[N*20],mark[N*20],marka[N*20],vv[N];
void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;}
void dfs(int x,int fa){
    start[x]=++cnt;vv[cnt]=1;
    for(int i=first[x];~i;i=next[i])
        if(v[i]!=fa)
            dfs(v[i],x);
    end[x]=++cnt;vv[cnt]=-1;
}
void push_down(int pos){
    int lson=pos<<1,rson=pos<<1|1;
    tree[lson]+=mark[lson]*marka[pos];
    tree[rson]+=mark[rson]*marka[pos];
    marka[lson]+=marka[pos];
    marka[rson]+=marka[pos];
    marka[pos]=0;
}
void build(int l,int r,int pos){
    if(l==r){mark[pos]=vv[l];return;}
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    build(l,mid,lson),build(mid+1,r,rson);
    mark[pos]=mark[lson]+mark[rson];
}
void insert(int l,int r,int pos,int wei,int x){
    if(l==r){tree[pos]+=wei;return;}
    if(marka[pos])push_down(pos);
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<x)insert(mid+1,r,rson,wei,x);
    else insert(l,mid,lson,wei,x);
    tree[pos]=tree[lson]+tree[rson];
}
int query(int l,int r,int pos,int x){
    if(r<=x){return tree[pos];}
    if(marka[pos])push_down(pos);
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid>=x)return query(l,mid,lson,x);
    else return query(l,mid,lson,x)+query(mid+1,r,rson,x);
}
void Change(int l,int r,int pos){
    if(l>=xx&&r<=yy){
        marka[pos]+=ww;
        tree[pos]+=ww*mark[pos];
        return;
    }
    if(marka[pos])push_down(pos);
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<xx)Change(mid+1,r,rson);
    else if(mid>=yy)Change(l,mid,lson);
    else Change(l,mid,lson),Change(mid+1,r,rson);
    tree[pos]=tree[lson]+tree[rson];
}
signed main(){
    memset(first,-1,sizeof(first));
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld",&Wei[i]);
    for(int i=1;i<n;i++)
        scanf("%lld%lld",&xx,&yy),add(xx,yy),add(yy,xx);
    dfs(1,-1);
    build(1,cnt,1);
    for(int i=1;i<=n;i++)
        insert(1,cnt,1,Wei[i],start[i]),insert(1,cnt,1,-Wei[i],end[i]);
    for(int i=1;i<=m;i++){
        scanf("%lld",&op);
        if(op==1){
            scanf("%lld%lld",&xx,&ww);
            insert(1,cnt,1,ww,start[xx]);
            insert(1,cnt,1,-ww,end[xx]);
        }
        else if(op==2){
            scanf("%lld%lld",&xx,&ww);
            yy=end[xx],xx=start[xx];
            Change(1,cnt,1);
        }
        else if(op==3){
            scanf("%lld",&xx);
            printf("%lld\n",query(1,cnt,1,start[xx]));
        }
    }
}

这里写图片描述

posted @ 2016-11-11 17:08  SiriusRen  阅读(243)  评论(0编辑  收藏  举报