文章总数30祭+CF383C Propagating tree

文章总数30祭+CF383C Propagating tree
题意:给出一棵n个结点的树,每个结点有一个权值,有m个操作,一个是给x结点加上val,并且给x的子节点加上-val(这里有传递性,子节点还要给其子节点加上-(-val))。另一个操作是查询某个结点的值。
还有,根是1
?
DFS序
把树拍扁拍成一个链
然后在上面用线段树维护
维护啥?
LZT(Lazzy Tag)
啥?没错,这题就是这么水,只用维护LZT即可
单点查询+区间修改。
单点查询so easy,但是区间修改…
定义两个LZT,LZT1和LZT2
记录链上每个点的深度的奇偶性
LZT1[i]表示第i个状态的给深度为奇数的点要加的值
LZT2[i]也同理
然后就好写了
std:

#include<bits/stdc++.h>
using namespace std;
const int N=500005;
int n,m;
int col[N];
int hed[N*2],tal[N*2],nxt[N*2],cnt=0;
int k[N];
int c[N];
int ll[N];
int rr[N];
int opt=0;
int t[N*10];
int dis[N];
int LZT1[N*10]={0};//LZT=0:不加不减 LZT>0 加 LZT<0 减  
int LZT2[N*10]={0};
int sec[N*10]={0};//sec=0:偶数层的  sec=1:奇数层的 sec=2:即有奇数层的也有偶数层的
//root=1
void push_up(int num){
    t[num]=t[num<<1]+t[num<<1|1];
}
void push_down(int l,int r,int num){
    LZT1[num<<1]+=LZT1[num];
    LZT1[num<<1|1]+=LZT1[num];
    LZT1[num]=0;
    LZT2[num<<1]+=LZT2[num];
    LZT2[num<<1|1]+=LZT2[num];
    LZT2[num]=0;
}
void addege(int x,int y){
    cnt++;
    tal[cnt]=y;
    nxt[cnt]=hed[x];
    hed[x]=cnt;
}
void dfs(int x,int father,int deep){
    k[++opt]=x;
    c[opt]=col[x];
    ll[x]=opt;
    dis[opt]=deep;
    for(int i=hed[x];i;i=nxt[i]){
        int v=tal[i];
        if(v==father) continue;
        dfs(v,x,deep+1);
    }
    k[++opt]=x;
    c[opt]=col[x];
    rr[x]=opt;
    dis[opt]=deep;
}
void build(int l,int r,int num){
    if(l==r){
        LZT1[num]=0;
        LZT2[num]=0;
        t[num]=c[l];
        sec[num]=dis[l]%2; 
        if(sec[num]==0) LZT2[num]=c[l];
        else LZT1[num]=c[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
    t[num]=t[num<<1]+t[num<<1|1];
    if(sec[num<<1]==sec[num<<1|1]) sec[num]=sec[num<<1];
    else sec[num]=2;
    LZT1[num]=0;
    LZT2[num]=0;
}
void add(int l,int r,int num,int L,int R,int v,int u){
    if(l>R||r<L) return;
    if(l>=L&&r<=R){
        if(u==1) LZT1[num]+=v,LZT2[num]-=v;
        else LZT1[num]-=v,LZT2[num]+=v;
        return;
    }
    int mid=(l+r)>>1;
    push_down(l,r,num);
    add(l,mid,num<<1,L,R,v,u);
    add(mid+1,r,num<<1|1,L,R,v,u);
} 
int ask(int l,int r,int num,int X){
// printf("** (%d-%d):%d %d**\n",l,r,num,X);
    if(l>X||r<X) return 0;
    if(l==r&&r==X){
    // for(int i=1;i<=50;i++) printf("%d %d **\n",LZT1[i],LZT2[i]);
        if(dis[X]%2==0) return LZT2[num];
        else return LZT1[num];
    }
    push_down(l,r,num);
    int mid=(l+r)>>1;
    if(mid>=X) return ask(l,mid,num<<1,X);
    else return ask(mid+1,r,num<<1|1,X);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&col[i]);
    }
    for(int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        addege(a,b);
        addege(b,a);
    } 
    dfs(1,0,1);
    build(1,2*n,1);
    for(int i=1;i<=m;i++){
        int opt,a,b;
        scanf("%d",&opt);
        if(opt==1){
            scanf("%d%d",&a,&b);
            int L=ll[a],R=rr[a];
            add(1,2*n,1,L,R,b,dis[L]%2);
        }
        else{
            //for(int i=1;i<=50;i++) printf("%d %d\n",LZT1[i],LZT2[i]);
            scanf("%d",&a);
            int X=ll[a];
            printf("%d\n",ask(1,2*n,1,X));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值