cf343dWater Tree(dfs序)

9 篇文章 0 订阅
2 篇文章 0 订阅

注意:dfs序不是欧拉序
三个操作:
1. 将u及其子树全部灌水,子树就是dfs序in[u]和out[u]中间那一部分
2. 将u及其祖先排水,暴力搞tle了,一点小优化仍然tle,其实只需要将u单点排水即可,因为询问u时,如果u或u的子树的某个节点是空的,那么u一定也应该是排水的(只是没有将它排水,排水的话就超时了)。
3. 询问u时,检查u及u的子树是否全部灌水了。
但,由于操作2,比如样例中的那棵树,
先1号节点灌水,3号节点排水,把2号节点灌水,此时就会出现1号节点本来应该是排水的了,但它及它的子树却全部灌水了。
所以操作1应加一步,判断这个区间是否是灌水状态,如果是排水,那么把u的fa排水。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <stack>
#include <vector>
#include <cstring>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;

const int MAXN=5e5+9;
struct _Edge
{
    int to,next;
}edge[MAXN<<1];
int hd[MAXN],tot,id;
int fa[MAXN],in[MAXN],out[MAXN];
void addedge(int u,int v)
{
    edge[tot].to=v;edge[tot].next=hd[u];hd[u]=tot++;
}
void dfs(int u,int pre)
{
    fa[u]=pre;
    in[u]=id++;
    for(int i=hd[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=pre) dfs(v,u);
    }
    out[u]=id++;
}
int tree[MAXN<<3],lazy[MAXN<<3];//dfs序本身就是2倍
void push_down(int tn,int l,int r)
{
    if(lazy[tn]!=-1){
        lazy[tn<<1]=lazy[tn<<1|1]=lazy[tn];
        tree[tn<<1]=tree[tn<<1|1]=lazy[tn];
        lazy[tn]=-1;
    }
}
void change(int tn,int l,int r,int x,int y,int op)
{
    if(x<=l&&r<=y) {tree[tn]=op;lazy[tn]=op;return;}
    push_down(tn,l,r);
    int mid=(l+r)>>1;
    if(x<=mid) change(tn<<1,l,mid,x,y,op);
    if(y>mid) change(tn<<1|1,mid+1,r,x,y,op);
    tree[tn]=min(tree[tn<<1],tree[tn<<1|1]);
}
bool query(int tn,int l,int r,int x,int y)
{
    if(x<=l&&r<=y) return tree[tn];
    push_down(tn,l,r);
    int mid=(l+r)>>1;
    if(y<=mid) return query(tn<<1,l,mid,x,y);
    else if(x>mid) return query(tn<<1|1,mid+1,r,x,y);
    else return query(tn<<1,l,mid,x,mid)&&query(tn<<1|1,mid+1,r,mid+1,y);
}
int main(int argc, char const *argv[])
{
    int n,q;
    msc(hd);
    tot=id=0;
    scanf("%d",&n);
    while(--n){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    dfs(1,0);
    ms(tree);
    msc(lazy);
    scanf("%d",&q);
    while(q--){
        int op,v;
        scanf("%d%d",&op,&v);
        if(op==3)   printf("%d\n",query(1,0,id-1,in[v],out[v]) );
        else if(op==1)  {
            bool tmp=query(1,0,id-1,in[v],out[v]);
            change(1,0,id-1,in[v],out[v],1);
            if(fa[v]&&!tmp) change(1,0,id-1,in[fa[v]],in[fa[v]],0);
        }
        else    change(1,0,id-1,in[v],in[v],0);//单点更新
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值