CF 343D D. Water Tree(思维,线段树)

网上都是树链剖分,咱不会啊。。。。。。
幸亏用简单线段树也能做,维护一颗树,一边是灌水树,用dfs序搞定,把灌水变成区间操作,开始为0,lazy更新从1开始的灌水时间。
一边是放水树,维护一颗最大树,每次放水更新一个点,更新从1开始的放水时间。
询问时,第一棵树找到询问点的值,第二棵树找到区间里最大值,如果第二棵树区间里最大值
大于第一棵树询问点的值,说明树的子树区间里有一个放水晚于灌水的,则为空。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#include <string>
#include <vector>
//#include <iostream>
using namespace std;


int dfsnum;
vector<int>mapp[510000];

struct node
{
    int ru,chu;
}inf[510000];

struct node0
{
    int jinshui,fangshui;
}tree[2110000];


int dfs(int now,int pre)
{
    dfsnum++;
    inf[now].ru=dfsnum;
    for(int i=0;i<mapp[now].size();i++)
    {
        if(mapp[now][i]==pre)
            continue;
        dfs(mapp[now][i],now);
    }
    inf[now].chu=dfsnum;
    return 0;
}



int change(int l,int r,int ll,int rr,int now,int num)
{
    if(ll<=l&&rr>=r)
    {
        tree[now].jinshui=num;
        return 0;
    }

    if(tree[now].jinshui!=0)
    {
        tree[now*2].jinshui=tree[now].jinshui;
        tree[now*2+1].jinshui=tree[now].jinshui;
        tree[now].jinshui=0;
    }


    if(rr<=(l+r)/2)
    change(l,(l+r)/2,ll,rr,now*2,num);
    else if(ll>=(l+r)/2+1)
    change((l+r)/2+1,r,ll,rr,now*2+1,num);
    else
    {
        change(l,(l+r)/2,ll,rr,now*2,num);
        change((l+r)/2+1,r,ll,rr,now*2+1,num);
    }


    return 0;
}

int thechange(int l,int r,int point,int now,int num)
{
    if(l==r)
    {
        tree[now].fangshui=num;
        return 0;
    }

    if(point<=(l+r)/2)
    thechange(l,(l+r)/2,point,now*2,num);
    else
    thechange((l+r)/2+1,r,point,now*2+1,num);

    tree[now].fangshui=max(tree[now*2].fangshui,tree[now*2+1].fangshui);

    return 0;
}




int question(int l,int r,int point,int now)
{
    if(l==r)
    {
        return tree[now].jinshui;
    }

    if(tree[now].jinshui!=0)
    {
        tree[now*2].jinshui=tree[now].jinshui;
        tree[now*2+1].jinshui=tree[now].jinshui;
        tree[now].jinshui=0;
    }

    if(point<=(l+r)/2)
    return question(l,(l+r)/2,point,now*2);
    else
    return question((l+r)/2+1,r,point,now*2+1);

}

int thequestion(int l,int r,int ll,int rr,int now)
{
    if(ll<=l&&rr>=r)
    {
        return tree[now].fangshui;
    }

    if(rr<=(l+r)/2)
    return thequestion(l,(l+r)/2,ll,rr,now*2);
    else if(ll>=(l+r)/2+1)
    return thequestion((l+r)/2+1,r,ll,rr,now*2+1);
    else return max(thequestion(l,(l+r)/2,ll,rr,now*2),thequestion((l+r)/2+1,r,ll,rr,now*2+1));

}




int main()
{
    int i,j,n,k,m,l,p;

    scanf("%d",&n);

    for(i=1;i<n;i++)
    {
        scanf("%d%d",&j,&k);
        mapp[j].push_back(k);
        mapp[k].push_back(j);
    }

    dfsnum=0;
    dfs(1,-1);

    scanf("%d",&m);

    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&j,&k);

        if(j==1)
        {
            change(1,n,inf[k].ru,inf[k].chu,1,i);
        }
        else if(j==2)
        {
            thechange(1,n,inf[k].ru,1,i);
        }
        else if(j==3)
        {
            l=question(1,n,inf[k].ru,1);
            p=thequestion(1,n,inf[k].ru,inf[k].chu,1);

            if(l==0&&p==0)
                printf("0\n");
            else if(p>l)
                printf("0\n");
            else
                printf("1\n");
        }
    }


    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值