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

来源:互联网 发布:office苹果mac版 编辑:程序博客网 时间:2024/05/06 05:25

题目链接: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|1const 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;}


原创粉丝点击