Codeforces 343 D Water Tree

12 篇文章 0 订阅

线段树……
题意:给定一棵树,以1为根,初始所有节点为0,有三种操作:
1、给节点x灌水,即x以及子树赋值为1;
2、给节点x排水,即x以及祖先赋值为0;
3、查询节点x是否有水……

样例:
Examples
input
5
1 2
5 1
2 3
4 2
12
1 1
2 3
3 1
3 2
3 3
3 4
1 2
2 4
3 1
3 3
3 4
3 5
output
0
0
0
1
0
1
0
1

对于操作1,首先查询节点x的子树里是否有0,如果有则将0“移动”到x的父亲,再进行区间修改;
对于操作2,单点修改为0即可;
对于操作3,查询x的子树是否有0即可;

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#define maxn 500000+10
#define _ const int&
#define mid ((l+r)>>1)
#define lc (t<<1)
#define rc ((t<<1)^1)
#define Moon for (int k=head[x];k;k=b[k].next)
using namespace std;
struct xx
{
    int v,next;
}b[maxn<<1];

int ll,rr,v,tag[maxn<<2],//子树被灌满水 
sz[maxn],num[maxn],dfn[maxn],T,Q,fa[maxn],x,y,n,head[maxn],m;

void add(_ u,_ v)
{
    b[++m]=(xx){v,head[u]};
    head[u]=m;
}

void dfs(_ x)//建树
{
    dfn[x]=++T;sz[x]=1;
    Moon
    {
        _ v=b[k].v;
        if (v==fa[x])continue;
        fa[v]=x;
        dfs(v);
        sz[x]+=sz[v];
    }
}

void maintain(_ t)//维护节点权值
{
    tag[t]=(tag[t<<1]==1)&&(tag[(t<<1)^1]==1)?1:0;
}

void pushdown(_ t)//下传标记
{
    if (tag[t]==0) return ;
    tag[lc]=tag[rc]=1;
    tag[t]=0;
    return ;
}

int find(_ l,_ r,_ t)//查询子树是否有0
{
    if (ll<=l&&r<=rr) return !tag[t];
    int ans=0;
    pushdown(t);
    if (ll<=mid) ans=ans||find(l,mid,lc);
    if (mid<rr)  ans=ans||find(mid+1,r,rc);
    maintain(t);
    return ans;
}

int update1(_ l,_ r,_ t)//区间[ll,rr]修改为1
{
    if (ll<=l&&r<=rr) return tag[t]=1;;
    pushdown(t);
    if (ll<=mid) update1(l,mid,lc);
    if (mid<rr)  update1(mid+1,r,rc);
    maintain(t);
}

int update2(_ l,_ r,_ t)//单点修改v为0
{
    //pushdown(t);//不要乱写pushdown这里坑了我灰常久…… 
    if (l==r) return tag[t]=0;  
    pushdown(t);
    v<=mid? update2(l,mid,lc):update2(mid+1,r,rc);
    maintain(t);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;++i) scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dfs(1);
    scanf("%d",&Q);
    while (Q--)
    {
        scanf("%d%d",&x,&y);
        ll=dfn[y],rr=dfn[y]+sz[y]-1;
        if (x==1) 
        {
            if (fa[y]&&find(1,n,1)) v=dfn[fa[y]],update2(1,n,1);    
            update1(1,n,1);
        }
        if (x==2) v=dfn[y],update2(1,n,1);
        if (x==3)find(1,n,1) ?puts("0"): puts("1");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值