HDU4553:约会安排(线段树)(第三部分 区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553

题目大意:查找是否有连续的空余时间

他的操作有三个 :

ds x  查找屌丝的时间有连续的x长度的空余时间

ns  x 为女神安排时间,先查找屌丝时间是否有空余,没有的话无视屌丝,直接判断女神时间是否有连续x长的空余时间

stduy a b  清空a到b区间的事情

思路:

一:存线段树数据的数组要有九个变量。

struct node
{
    int d,n,s;//d屌丝延迟标记 n女神延迟标记  s学习延迟标记
    int ls,rs,ms;//屌丝的左 右 区间最大的连续空时间的长
    int nsl,nsr,nsm;//女神的左 右 区间最大的连续空时间的长
} a[L<<2];
二:关于pushdown函数

void pushdown(int l,int r,int rt)//延迟标记的向下传递
{
    int m = (l+r)>>1;
    if(a[rt].s)
    {
        xuexi(lson);
        xuexi(rson);
        a[rt].s = 0;
    }
    if(a[rt].d)
    {
        diaosi(lson);
        diaosi(rson);
        a[rt].d = 0;
    }
    if(a[rt].n)
    {
        nvshen(lson);
        nvshen(rson);
        a[rt].n = 0;
    }
}

pushdown函数是将延迟标记的信息向下传递

而延迟标记有三种  学习,屌丝,女神,注意学习标记优先级最大 

分别对每种标记有如下的操作:

void diaosi(int l,int r,int rt)//屌丝的延迟标记处理
{
    a[rt].d = 1;
    a[rt].ls = a[rt].rs = a[rt].ms = 0;
}

void nvshen(int l,int r,int rt)//女神的延迟标记处理  不仅要将屌丝时间占据 女神时间也要占据
{
    a[rt].n = 1;
    a[rt].d = 0;
    a[rt].ls = a[rt].rs = a[rt].ms = 0;
    a[rt].nsl = a[rt].nsr = a[rt].nsm = 0;
}

void xuexi(int l,int r,int rt)//学习延迟标记  全部清理成空的时间
{
    a[rt].s = 1;
    a[rt].d = a[rt].n = 0;
    a[rt].ls = a[rt].rs = a[rt].ms = r-l+1;
    a[rt].nsl = a[rt].nsr = a[rt].nsm = r-l+1;
}

这里需要特别注意的是女神标记的处理,他不仅要对自己女神时间进行处理,同时也要对相应的屌丝时间进行处理

三:关于pushup函数

void pushup(int l,int r,int rt)//屌丝和女神区间的合并
{
    int mid = (l+r)>>1;
    int m=r-l+1;
    a[rt].ms = max(a[rt<<1].ms,a[rt<<1|1].ms);
    a[rt].ms = max(a[rt].ms,a[rt<<1].rs+a[rt<<1|1].ls);
    a[rt].ls = a[rt<<1].ls;
    a[rt].rs = a[rt<<1|1].rs;
    if(a[rt<<1].ls == m-(m>>1))
        a[rt].ls+=a[rt<<1|1].ls;
    if(a[rt<<1|1].rs == (m>>1))
        a[rt].rs+= a[rt<<1].rs;

    a[rt].nsm = max(a[rt<<1].nsm,a[rt<<1|1].nsm);
    a[rt].nsm = max(a[rt].nsm,a[rt<<1].nsr+a[rt<<1|1].nsl);
    a[rt].nsl = a[rt<<1].nsl;
    a[rt].nsr = a[rt<<1|1].nsr;
    if(a[rt<<1].nsl == m-(m>>1))
        a[rt].nsl+=a[rt<<1|1].nsl;
    if(a[rt<<1|1].nsr ==(m>>1))
        a[rt].nsr+= a[rt<<1].nsr;
}

这个就是一个典型的区间合并  女神和屌丝同样处理

四:查找连续长度为t的连续区间  注意一个是屌丝查询  一个是女神查询 分开处理

int query(int flag,int t,int l,int r,int rt)
{
    if(l==r)
        return l;
    int m = (l+r)>>1;
    pushdown(l,r,rt);
    if(!flag)//屌丝时间查询
    {
        if(a[rt<<1].ms>=t)//左子树有时间
            return query(flag,t,lson);
        else if(a[rt<<1].rs+a[rt<<1|1].ls>=t)//左子树部分加右子树部分
            return m-a[rt<<1].rs+1;
        else//右子树有时间
            return query(flag,t,rson);
    }
    else//女神时间查询  直接无视屌丝
    {
        if(a[rt<<1].nsm>=t)
            return query(flag,t,lson);
        else if(a[rt<<1].nsr+a[rt<<1|1].nsl>=t)
            return m-a[rt<<1].nsr+1;
        else
            return query(flag,t,rson);
    }
}


因为要求时间尽可能早,所有从左子树开始查询,然后左部分加右部分,最后是右子树

五:对区间进行处理  将其覆盖成屌丝时间或者女神时间

 

void insert(int flag,int L,int R,int l,int r,int rt)
{
    if(l == L && r == R)
    {
        if(!flag)//将那段时间设为屌丝时间
            diaosi(l,r,rt);
        else//将那段时间设为女神时间
            nvshen(l,r,rt);
        return ;
    }
    int m = (l+r)>>1;
    pushdown(l,r,rt);
    if(R<=m)
        insert(flag,L,R,lson);
    else if(L>m)
        insert(flag,L,R,rson);
    else
    {
        insert(flag,L,m,lson);
        insert(flag,m+1,R,rson);
    }
    pushup(l,r,rt);
}

接下里是完整的ac代码

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int L = 100000+10;

struct node
{
    int d,n,s;//d屌丝延迟标记 n女神延迟标记  s学习延迟标记
    int ls,rs,ms;//屌丝的左 右 区间最大的连续空时间的长
    int nsl,nsr,nsm;//女神的左 右 区间最大的连续空时间的长
} a[L<<2];

void diaosi(int l,int r,int rt)//屌丝的延迟标记处理
{
    a[rt].d = 1;
    a[rt].ls = a[rt].rs = a[rt].ms = 0;
}

void nvshen(int l,int r,int rt)//女神的延迟标记处理  不仅要将屌丝时间占据 女神时间也要占据
{
    a[rt].n = 1;
    a[rt].d = 0;
    a[rt].ls = a[rt].rs = a[rt].ms = 0;
    a[rt].nsl = a[rt].nsr = a[rt].nsm = 0;
}

void xuexi(int l,int r,int rt)//学习延迟标记  全部清理成空的时间
{
    a[rt].s = 1;
    a[rt].d = a[rt].n = 0;
    a[rt].ls = a[rt].rs = a[rt].ms = r-l+1;
    a[rt].nsl = a[rt].nsr = a[rt].nsm = r-l+1;
}

void pushup(int l,int r,int rt)//屌丝和女神区间的合并
{
    int mid = (l+r)>>1;
    int m=r-l+1;
    a[rt].ms = max(a[rt<<1].ms,a[rt<<1|1].ms);
    a[rt].ms = max(a[rt].ms,a[rt<<1].rs+a[rt<<1|1].ls);
    a[rt].ls = a[rt<<1].ls;
    a[rt].rs = a[rt<<1|1].rs;
    if(a[rt<<1].ls == m-(m>>1))
        a[rt].ls+=a[rt<<1|1].ls;
    if(a[rt<<1|1].rs == (m>>1))
        a[rt].rs+= a[rt<<1].rs;

    a[rt].nsm = max(a[rt<<1].nsm,a[rt<<1|1].nsm);
    a[rt].nsm = max(a[rt].nsm,a[rt<<1].nsr+a[rt<<1|1].nsl);
    a[rt].nsl = a[rt<<1].nsl;
    a[rt].nsr = a[rt<<1|1].nsr;
    if(a[rt<<1].nsl == m-(m>>1))
        a[rt].nsl+=a[rt<<1|1].nsl;
    if(a[rt<<1|1].nsr ==(m>>1))
        a[rt].nsr+= a[rt<<1].nsr;
}

void pushdown(int l,int r,int rt)//延迟标记的向下传递
{
    int m = (l+r)>>1;
    if(a[rt].s)
    {
        xuexi(lson);
        xuexi(rson);
        a[rt].s = 0;
    }
    if(a[rt].d)
    {
        diaosi(lson);
        diaosi(rson);
        a[rt].d = 0;
    }
    if(a[rt].n)
    {
        nvshen(lson);
        nvshen(rson);
        a[rt].n = 0;
    }
}

void study(int L,int R,int l,int r,int rt)
{
    if(L == l && R == r)
    {
        xuexi(l,r,rt);
        return ;
    }
    int m = (l+r)>>1;
    pushdown(l,r,rt);
    if(R<=m)
        study(L,R,lson);
    else if(L>m)
        study(L,R,rson);
    else
    {
        study(L,m,lson);
        study(m+1,R,rson);
    }
    pushup(l,r,rt);
}


void insert(int flag,int L,int R,int l,int r,int rt)
{
    if(l == L && r == R)
    {
        if(!flag)//将那段时间设为屌丝时间
            diaosi(l,r,rt);
        else//将那段时间设为女神时间
            nvshen(l,r,rt);
        return ;
    }
    int m = (l+r)>>1;
    pushdown(l,r,rt);
    if(R<=m)
        insert(flag,L,R,lson);
    else if(L>m)
        insert(flag,L,R,rson);
    else
    {
        insert(flag,L,m,lson);
        insert(flag,m+1,R,rson);
    }
    pushup(l,r,rt);
}

int query(int flag,int t,int l,int r,int rt)
{
    if(l==r)
        return l;
    int m = (l+r)>>1;
    pushdown(l,r,rt);
    if(!flag)//屌丝时间查询
    {
        if(a[rt<<1].ms>=t)//左子树有时间
            return query(flag,t,lson);
        else if(a[rt<<1].rs+a[rt<<1|1].ls>=t)//左子树部分加右子树部分
            return m-a[rt<<1].rs+1;
        else//右子树有时间
            return query(flag,t,rson);
    }
    else//女神时间查询  直接无视屌丝
    {
        if(a[rt<<1].nsm>=t)
            return query(flag,t,lson);
        else if(a[rt<<1].nsr+a[rt<<1|1].nsl>=t)
            return m-a[rt<<1].nsr+1;
        else
            return query(flag,t,rson);
    }
}


int main()
{
    int t,i,x,y,ans,cas = 1,n,m;
    char str[20];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        printf("Case %d:\n",cas++);
        study(1,n,1,n,1);   //区间1~n全部清零
        while(m--)
        {
            scanf("%s",str);
            if(str[0] == 'D')
            {
                scanf("%d",&x);
                if(a[1].ms<x)//线段树最大的区间都小于给定的时间就不用找了
                    printf("fly with yourself\n");
                else
                {
                    ans = query(0,x,1,n,1);//查询到位置
                    insert(0,ans,ans+x-1,1,n,1);
                    printf("%d,let's fly\n",ans);
                }
            }
            else if(str[0] == 'N')
            {
                scanf("%d",&x);
                if(a[1].ms<x)//屌丝时间找不到空余时间
                {
                    if(a[1].nsm<x)//判断女神时间是否有空余
                        printf("wait for me\n");
                    else
                    {
                        ans = query(1,x,1,n,1);//先查找位置
                        insert(1,ans,ans+x-1,1,n,1);//然后对其区间进行更新
                        printf("%d,don't put my gezi\n",ans);
                    }
                }
                else
                {
                    ans = query(0,x,1,n,1);
                    insert(1,ans,ans+x-1,1,n,1);
                    printf("%d,don't put my gezi\n",ans);
                }
            }
            else
            {
                scanf("%d%d",&x,&y);
                study(x,y,1,n,1);
                printf("I am the hope of chinese chengxuyuan!!\n");
            }
        }
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值