Codeforces 343D Water Tree 题解&代码

其实是树剖QwQ不过个人感觉和线段树还是很像的…所以树剖的本质大约就是dfs序+线段树?

in[]记录节点的节点的dfs编号
out[]记录节点的控制范围
(in[i]<=in[j]<=out[i]当且仅当j节点属于以i为根节点的子树)
pos[i]记录i节点的父亲节点
这样就能用[1,n]表示一颗以1为根节点的树了

1、每次要给i节点加水的时候就把[in[i],out[i]]的值修改为1,用lazy标记的方式很容易做到
**如果给i节点加水的时候发现有子节点是空的,那么说明i节点的父亲节点一定是空的【否则作为i节点的父亲节点,如果它有水它的子节点一定都是有水的】,如此递推,可以很容易发现此时从i节点父亲向上的祖先全部都是空的,这样就可以把加水后的问题转化为将i的父亲节点清空,父亲节点的查找在dfs时已经提前记录,新问题也就很容易转化为问题2

2、由根向下找到将要清空的点i(即区间[in[i],in[i]]),每一步都pushdown一次,将该点的值修改为0,然后在回溯时每一步都重置节点【如果子节点有空节点,父节点必然是空节点】

3、查询点i状态(区间[in[i],in[i]]),记得每一步都pushdown即可

#include<iostream>
#include<vector>
#include<stdio.h>
#include<windows.h>
#define lson (o<<1)
#define rson ((o<<1)|1)
using namespace std;
const int maxn=500005;
vector<int> edge[maxn];
int n,q,a[maxn],b[maxn],in[maxn],out[maxn],pos[maxn],c,v,tot;
bool lazy[maxn*4],tree[maxn*4],ans;
void dfs(int x,int pre)
{
    in[x]=++tot;
    for(int i=0;i<edge[x].size();i++)
        if(edge[x][i]!=pre)
            pos[edge[x][i]]=x,dfs(edge[x][i],x);
    out[x]=tot;
}
void pushdown(int o,int l,int r)
{
    if(lazy[o])
        if(l==r)tree[o]=1;
        else tree[o]=tree[lson]=tree[rson]=lazy[lson]=lazy[rson]=1;
    lazy[o]=0;
}
void maintain(int o,int l,int r)
{
    if(l!=r)tree[o]=tree[lson] && tree[rson];
}
void fillwater(int o,int l,int r)
{
    pushdown(o,l,r);
    if(l>=in[v] && r<=out[v])
    {
        //cout<<in[v]<<' '<<out[v]<<' '<<o<<' '<<l<<' '<<r<<endl;
        ans&=tree[o];
        lazy[o]=1;
        pushdown(o,l,r);
        return;
    }
    if(l>out[v] || r<in[v])return;
    int mid=(l+r)/2;
    fillwater(lson,l,mid);
    fillwater(rson,mid+1,r);
    maintain(o,l,r);
}
void emptywater(int o,int l,int r)
{
    pushdown(o,l,r);
    if(l>in[v] || r<in[v])return;
    if(l==r)
    {
        //cout<<in[v]<<' '<<out[v]<<' '<<o<<' '<<l<<' '<<r<<endl;
        pushdown(o,l,r);
        tree[o]=0;
        return;
    }
    int mid=(l+r)/2;
    emptywater(lson,l,mid);
    emptywater(rson,mid+1,r);
    maintain(o,l,r);
}
void query(int o,int l,int r)
{
    //cout<<tree[o]<<' '<<o<<' '<<l<<' '<<r<<endl;
    pushdown(o,l,r);
    if(l>=in[v] && r<=out[v])
    {
        pushdown(o,l,r);
        ans&=tree[o];
        return;
    }
    if(l>out[v] || r<in[v])return;
    int mid=(l+r)/2;
    query(lson,l,mid);
    query(rson,mid+1,r);
}
int main(void)
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a[i],&b[i]);
        edge[a[i]].push_back(b[i]);
        edge[b[i]].push_back(a[i]);
    }
    //cout<<"dfs"<<endl;
    dfs(1,0);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&c,&v);
        //cout<<"que"<<' '<<in[v]<<' '<<out[v]<<endl;
        //Sleep(2000);
        if(c==1)
        {
            ans=1;
            fillwater(1,1,tot);
            v=pos[v];
            if(v && (!ans))emptywater(1,1,tot);
        }
        if(c==2)emptywater(1,1,tot);
        if(c==3)ans=1,query(1,1,tot),printf("%d\n",(int)ans);
        //cout<<c<<endl;
    }
    //cin>>n;
    return 0;
}

你可能感兴趣的:(C++,线段树,DFS,codeforces,树链剖分)