Codeforces 343 D.water tree ( 树链剖分 )

链接 water tree

题意:
给一颗树,初始节点值为 0 ,三个操作

  1. 将 x 的子树节点值变成 1.
  2. 将 x 的父节点值变成 0.
  3. 查询 x 节点的值。

思路:
树链剖分模板,1 2 操作分别对应 子树修改 和 链修改 (1-x),3操作为单点查询。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll ;
const int maxn=1e6+7;

ll sum[maxn<<2],lazy[maxn<<2],val[maxn],p,n,m;
int depth[maxn],siz[maxn],fa[maxn],son[maxn],cnt,id[maxn],tot[maxn],num,head[maxn<<1];
struct node{
     int u,v,next;
}e[maxn<<1];
void add(int u,int v){
     e[++num].next=head[u];
     e[num].v=v;
     head[u]=num;
}
void dfs1(int u,int pre,int dep){
     depth[u]=dep; siz[u]=1; fa[u]=pre;

     for(int i=head[u]; i; i=e[i].next){
        int to = e[i].v;
        if( to == pre) continue;
        dfs1(to,u,dep+1);
        siz[u]+=siz[to];
        if(siz[to]>siz[son[u]]) son[u]=to;  //更新重儿子

     }
}
void dfs2(int u,int t){
    id[u]=++cnt;               //赋予新的序列号
    tot[u]=t;                  //重边顶点
    if(son[u]) dfs2(son[u],t); //优先对重链编号
    for(int i=head[u];i;i=e[i].next){
        int to=e[i].v;
        if(to!=son[u]&&to!=fa[u])  //跳过重儿子和父节点
            dfs2(to,to);       //非重儿子的 tot是本身
    }
}
void pushdown(int rt,int l,int r){
    int m=(l+r)>>1;
    if(lazy[rt]!=-1){
        lazy[rt<<1]=lazy[rt];
        lazy[rt<<1|1]=lazy[rt];
        sum[rt<<1]=lazy[rt];
        sum[rt<<1|1]=lazy[rt];
        lazy[rt]=-1;
    }
}
void build(int l,int r,int rt){
    if(l==r){
        lazy[rt]=-1;
        sum[rt]=0;
        return ;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
}
void update(int x,int y,int v,int l,int r,int rt){
     if(x<=l&&y>=r){
        lazy[rt]=v;
        sum[rt]=v;
        return ;
     }
     pushdown(rt,l,r);
     int m=(l+r)>>1;
     if(x<=m) update(x,y,v,l,m,rt<<1);
     if(y>m) update(x,y,v,m+1,r,rt<<1|1);
}
ll query(int id,int l,int r,int rt){
     ll s=0;
     if(l==r){
        return sum[rt];
     }
     pushdown(rt,l,r);
     int m=(l+r)>>1;
     if(id<=m) return query(id,l,m,rt<<1);
     if(id>m)  return query(id,m+1,r,rt<<1|1);
}
void add_v(int x,int y,int v){
     while(tot[x]!=tot[y]){
         if(depth [tot[x]]< depth[tot[y]]) swap(x,y);
         update( id [tot[x]],id[x],v,1,n,1);
         x=fa[tot[x]];
     }
     if(depth[x]>depth[y]) swap(x,y);
     update(id[x],id[y],v,1,n,1);
}
int main (){
    cin>>n;
    for(int i=0,u,v;i<n-1;i++){
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs1(1,-1,0);dfs2(1,1);
    build(1,n,1);
    cin>>m;
    for(int i=0;i<m;i++){
        int t,x;
        scanf("%d%d",&t,&x);
        if(t==2) add_v(1,x,0);

        if(t==1) update(id[x],id[x]+siz[x]-1,1,1,n,1);

        if(t==3) printf ("%d\n",query(id[x],1,n,1));

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值