HDU4553 约会安排

这道题是在告诉我们如何成为时间管理大师(逃


题目大意

一开始给予你长度为 \(n\) 的一个空串,接下来给予你3种操作:

\(DS~x\) :寻找串中长度大于等于 \(x\)\(0\) 串中最靠左的一个,输出他的左边界 \(l\) 和一个奇怪的字符串 \(",let's~fly"\) ,并将 \(l\)\((l+x-1)\) 都变为 \(1\) 。否则输出字符串 \("fly~with~ your~self"\)

\(NS~x\) :先寻找串中长度大于等于 \(x\)\(0\) 串中最靠左的一个,若没有,则寻找 \(01\) 串中符合条件的。两次若有一次找到,则输出该子串的左边界 \(l\) 和字符串 \(",don't~put~my~gezi"\) ,并将 \(l\)\((l+x-1)\) 都变为 \(2\) 。否则输出字符串 \("wait~for~me"\)

\(STUDY!!~x~y\) :将串从 \(x\)\(y\) 都清零,并输出 \("I~am~the~hope~of~chinese~chengxuyuan!!"\)

题解

这是线段树的一种应用。

我们可以易得,寻找 \(0\) 串和 \(01\) 串的操作是完全等价的,只是需要处理的数据不一样,但都是寻找符合条件的最长串。

因此,我们对于每一个线段树的节点都维护 \(4\) 个变量 \(l\)\(r\)\(mx\)\(loc\),分别为以左边界为一端的最长串长度,以右边界为一端的最长串长度,该区间的最长串长度,该区间最长串的左边界。

根据变量的定义,我们可以轻易得出状态转移方程:

\[tr_p.mx=max(tr_{ls}.r+tr_{rs}.l,tr_{ls}.mx,tr_{rs}.mx) \]

\[tr_p.l= \begin{cases} tr_{ls}.l+tr_{rs}.l&tr_{ls}=mid-l+1\\ tr_{ls}.l&else \end{cases} \]

\[tr_p.r= \begin{cases} tr_{rs}.r+tr_{ls}.r&tr_{rs}=r-mid\\ tr_{rs}.r&else \end{cases} \]

代码如下:

void up(int p,int l,int r)
{
    int mid=(l+r)>>1;
    tr[p].dmx=max(tr[p<<1].dr+tr[p<<1|1].dl,max(tr[p<<1].dmx,tr[p<<1|1].dmx));
    if(tr[p].dmx==tr[p<<1].dmx)
    tr[p].dloc=tr[p<<1].dloc;
    else  if(tr[p].dmx==tr[p<<1].dr+tr[p<<1|1].dl)
    tr[p].dloc=mid-tr[p<<1].dr+1;
    else
    tr[p].dloc=tr[p<<1|1].dloc;
    if(tr[p<<1].dl==mid-l+1)
    tr[p].dl=tr[p<<1].dl+tr[p<<1|1].dl;
    else
    tr[p].dl=tr[p<<1].dl;
    if(tr[p<<1|1].dr==r-mid)
    tr[p].dr=tr[p<<1|1].dr+tr[p<<1].dr;
    else
    tr[p].dr=tr[p<<1|1].dr;

    tr[p].nmx=max(tr[p<<1].nr+tr[p<<1|1].nl,max(tr[p<<1].nmx,tr[p<<1|1].nmx));
    if(tr[p].nmx==tr[p<<1].nmx)
    tr[p].nloc=tr[p<<1].nloc;
    else if(tr[p].nmx==tr[p<<1].nr+tr[p<<1|1].nl)
    tr[p].nloc=mid-tr[p<<1].nr+1;
    else
    tr[p].nloc=tr[p<<1|1].nloc;
    if(tr[p<<1].nl==mid-l+1)
    tr[p].nl=tr[p<<1].nl+tr[p<<1|1].nl;
    else
    tr[p].nl=tr[p<<1].nl;
    if(tr[p<<1|1].nr==r-mid)
    tr[p].nr=tr[p<<1|1].nr+tr[p<<1].nr;
    else
    tr[p].nr=tr[p<<1|1].nr;
    return ;
}

同时针对每一种操作,我们就像普通的线段树一样,存一个 \(lazytag\) ,来记录当前节点的子树需要进行的操作,但是在进行 \(pushdown\) 操作的时候,我们需要谨慎考虑每一种操作的优先级,在这里是 \(STUDY!!>NS>DS\) ,也就是说前者可以覆盖后者的操作。这里是很关键的一个细节问题。

代码如下:

void down(int p,int l,int r)
{
    int mid=(l+r)>>1;
    if(tr[p].clean)
    {
        tr[p<<1].dl=tr[p<<1].dr=tr[p<<1].dmx=mid-l+1;
        tr[p<<1].dloc=l;
        tr[p<<1].nl=tr[p<<1].nr=tr[p<<1].nmx=mid-l+1;
        tr[p<<1].nloc=l;
        tr[p<<1].data=0;
        tr[p<<1].clean=1;
        tr[p<<1|1].dl=tr[p<<1|1].dr=tr[p<<1|1].dmx=r-mid;
        tr[p<<1|1].dloc=mid+1;
        tr[p<<1|1].nl=tr[p<<1|1].nr=tr[p<<1|1].nmx=r-mid;
        tr[p<<1|1].nloc=mid+1;
        tr[p<<1|1].data=0;
        tr[p<<1|1].clean=1;
        tr[p].clean=0;
    }
    if(tr[p].data==1)
    {
        tr[p<<1].dl=tr[p<<1].dr=tr[p<<1].dmx=0;
        tr[p<<1].dloc=l;
        tr[p<<1].data=1;
        tr[p<<1|1].dl=tr[p<<1|1].dr=tr[p<<1|1].dmx=0;
        tr[p<<1|1].dloc=mid+1;
        tr[p<<1|1].data=1;
        tr[p].data=0;
    }
    if(tr[p].data==2)
    {
        tr[p<<1].dl=tr[p<<1].dr=tr[p<<1].dmx=0;
        tr[p<<1].dloc=l;
        tr[p<<1].nl=tr[p<<1].nr=tr[p<<1].nmx=0;
        tr[p<<1].nloc=l;
        tr[p<<1].data=2;
        tr[p<<1|1].dl=tr[p<<1|1].dr=tr[p<<1|1].dmx=0;
        tr[p<<1|1].dloc=mid+1;
        tr[p<<1|1].nl=tr[p<<1|1].nr=tr[p<<1|1].nmx=0;
        tr[p<<1|1].nloc=mid+1;
        tr[p<<1|1].data=2;
        tr[p].data=0;
    }
}

\(pushup\)\(pushdown\) 的操作处理好后,我们考虑如何查询,因为我们要找到尽量左边的串,所以对于每一个节点,我们先考虑这个点最大的串的长度是否符合条件,不符合条件则返回 \(0\) ,否则我们则依次判断左节点,合并串,右节点,来找到最左边的符合要求的串。

代码如下(以寻找 \(0\) 串为例):

int queryd(int p,int l,int r,int len)
{
    // printf("%d %d %d %d\n",l,r,tr[p].dmx,tr[p].data);
    if(tr[p].dmx<len)
    return 0;
    if(l==r)
    return tr[p].dloc;
    down(p,l,r);
    // printf("%d %d %d\n",tr[p<<1].dmx,tr[p<<1].dr+tr[p<<1|1].dl,tr[p<<1|1].dmx);
    int mid=(l+r)>>1;
    if(tr[p<<1].dmx>=len)
    return queryd(p<<1,l,mid,len);
    if(tr[p<<1].dr+tr[p<<1|1].dl>=len)
    return mid-tr[p<<1].dr+1;
    return queryd(p<<1|1,mid+1,r,len);
}

附上完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N=500005;
int n,m;
string ord;
int x,y;
struct SegNode
{
    int data;
    bool clean;
    int dl,dmx,dr,dloc;
    int nl,nmx,nr,nloc;
}tr[N<<2];
void up(int p,int l,int r)
{
    int mid=(l+r)>>1;
    tr[p].dmx=max(tr[p<<1].dr+tr[p<<1|1].dl,max(tr[p<<1].dmx,tr[p<<1|1].dmx));
    if(tr[p].dmx==tr[p<<1].dmx)
    tr[p].dloc=tr[p<<1].dloc;
    else  if(tr[p].dmx==tr[p<<1].dr+tr[p<<1|1].dl)
    tr[p].dloc=mid-tr[p<<1].dr+1;
    else
    tr[p].dloc=tr[p<<1|1].dloc;
    if(tr[p<<1].dl==mid-l+1)
    tr[p].dl=tr[p<<1].dl+tr[p<<1|1].dl;
    else
    tr[p].dl=tr[p<<1].dl;
    if(tr[p<<1|1].dr==r-mid)
    tr[p].dr=tr[p<<1|1].dr+tr[p<<1].dr;
    else
    tr[p].dr=tr[p<<1|1].dr;

    tr[p].nmx=max(tr[p<<1].nr+tr[p<<1|1].nl,max(tr[p<<1].nmx,tr[p<<1|1].nmx));
    if(tr[p].nmx==tr[p<<1].nmx)
    tr[p].nloc=tr[p<<1].nloc;
    else if(tr[p].nmx==tr[p<<1].nr+tr[p<<1|1].nl)
    tr[p].nloc=mid-tr[p<<1].nr+1;
    else
    tr[p].nloc=tr[p<<1|1].nloc;
    if(tr[p<<1].nl==mid-l+1)
    tr[p].nl=tr[p<<1].nl+tr[p<<1|1].nl;
    else
    tr[p].nl=tr[p<<1].nl;
    if(tr[p<<1|1].nr==r-mid)
    tr[p].nr=tr[p<<1|1].nr+tr[p<<1].nr;
    else
    tr[p].nr=tr[p<<1|1].nr;
    return ;
}
void down(int p,int l,int r)
{
    int mid=(l+r)>>1;
    if(tr[p].clean)
    {
        tr[p<<1].dl=tr[p<<1].dr=tr[p<<1].dmx=mid-l+1;
        tr[p<<1].dloc=l;
        tr[p<<1].nl=tr[p<<1].nr=tr[p<<1].nmx=mid-l+1;
        tr[p<<1].nloc=l;
        tr[p<<1].data=0;
        tr[p<<1].clean=1;
        tr[p<<1|1].dl=tr[p<<1|1].dr=tr[p<<1|1].dmx=r-mid;
        tr[p<<1|1].dloc=mid+1;
        tr[p<<1|1].nl=tr[p<<1|1].nr=tr[p<<1|1].nmx=r-mid;
        tr[p<<1|1].nloc=mid+1;
        tr[p<<1|1].data=0;
        tr[p<<1|1].clean=1;
        tr[p].clean=0;
    }
    if(tr[p].data==1)
    {
        tr[p<<1].dl=tr[p<<1].dr=tr[p<<1].dmx=0;
        tr[p<<1].dloc=l;
        tr[p<<1].data=1;
        tr[p<<1|1].dl=tr[p<<1|1].dr=tr[p<<1|1].dmx=0;
        tr[p<<1|1].dloc=mid+1;
        tr[p<<1|1].data=1;
        tr[p].data=0;
    }
    if(tr[p].data==2)
    {
        tr[p<<1].dl=tr[p<<1].dr=tr[p<<1].dmx=0;
        tr[p<<1].dloc=l;
        tr[p<<1].nl=tr[p<<1].nr=tr[p<<1].nmx=0;
        tr[p<<1].nloc=l;
        tr[p<<1].data=2;
        tr[p<<1|1].dl=tr[p<<1|1].dr=tr[p<<1|1].dmx=0;
        tr[p<<1|1].dloc=mid+1;
        tr[p<<1|1].nl=tr[p<<1|1].nr=tr[p<<1|1].nmx=0;
        tr[p<<1|1].nloc=mid+1;
        tr[p<<1|1].data=2;
        tr[p].data=0;
    }
}
void build(int p,int l,int r)
{
    tr[p].data=0;
    if(l==r)
    {
        tr[p].dl=tr[p].dr=tr[p].dmx=1;
        tr[p].nl=tr[p].nr=tr[p].nmx=1;
        tr[p].dloc=tr[p].nloc=l;
        return ;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    up(p,l,r);
    return ;
}
void add(int p,int l,int r,int x,int y,int z)
{
    if(x<=l&&r<=y)
    {
        if(z==1)
        {
            tr[p].dl=tr[p].dr=tr[p].dmx=0;
            tr[p].dloc=l;
            tr[p].data=1;
        }
        if(z==2)
        {
            tr[p].dl=tr[p].dr=tr[p].dmx=0;
            tr[p].dloc=l;
            tr[p].nl=tr[p].nr=tr[p].nmx=0;
            tr[p].nloc=l;
            tr[p].data=2;
        }
        if(z==3)
        {
            tr[p].dl=tr[p].dr=tr[p].dmx=r-l+1;
            tr[p].dloc=l;
            tr[p].nl=tr[p].nr=tr[p].nmx=r-l+1;
            tr[p].nloc=l;
            tr[p].data=0;
            tr[p].clean=1;
        }
        return ;
    }
    down(p,l,r);
    int mid=(l+r)>>1;
    if(x<=mid)
    add(p<<1,l,mid,x,y,z);
    if(y>=mid+1)
    add(p<<1|1,mid+1,r,x,y,z);
    up(p,l,r);
    return ;
}
int queryd(int p,int l,int r,int len)
{
    // printf("%d %d %d %d\n",l,r,tr[p].dmx,tr[p].data);
    if(tr[p].dmx<len)
    return 0;
    if(l==r)
    return tr[p].dloc;
    down(p,l,r);
    // printf("%d %d %d\n",tr[p<<1].dmx,tr[p<<1].dr+tr[p<<1|1].dl,tr[p<<1|1].dmx);
    int mid=(l+r)>>1;
    if(tr[p<<1].dmx>=len)
    return queryd(p<<1,l,mid,len);
    if(tr[p<<1].dr+tr[p<<1|1].dl>=len)
    return mid-tr[p<<1].dr+1;
    return queryd(p<<1|1,mid+1,r,len);
}
int queryn(int p,int l,int r,int len)
{
    // printf("%d %d %d %d\n",l,r,tr[p].nmx,tr[p].data);
    if(tr[p].nmx<len)
    return 0;
    if(l==r)
    return tr[p].nloc;
    down(p,l,r);
    // printf("%d %d %d\n",tr[p<<1].nmx,tr[p<<1].nr+tr[p<<1|1].nl,tr[p<<1|1].nmx);
    int mid=(l+r)>>1;
    if(tr[p<<1].nmx>=len)
    return queryn(p<<1,l,mid,len);
    if(tr[p<<1].nr+tr[p<<1|1].nl>=len)
    return mid-tr[p<<1].nr+1;
    return queryn(p<<1|1,mid+1,r,len);
}
void solve()
{
    cin>>n>>m;
    build(1,1,n);
    for(int i=1;i<=m;++i)
    {
        cin>>ord;
        if(ord=="DS")
        {
            scanf("%d",&x);
            int tmp=queryd(1,1,n,x);
            if(tmp==0)
            printf("fly with yourself\n");
            else
            printf("%d,let's fly\n",tmp);
            if(tmp)
            add(1,1,n,tmp,tmp+x-1,1);
        }
        else if(ord=="NS")
        {
            scanf("%d",&x);
            int tmp=queryd(1,1,n,x);
            if(tmp==0)
            {
                tmp=queryn(1,1,n,x);
                if(tmp==0)
                printf("wait for me\n");
                else
                printf("%d,don't put my gezi\n",tmp);
            }
            else
            printf("%d,don't put my gezi\n",tmp);
            if(tmp)
            add(1,1,n,tmp,tmp+x-1,2);
        }
       else
        {
           scanf("%d%d",&x,&y);
           printf("I am the hope of chinese chengxuyuan!!\n");
           add(1,1,n,x,y,3);
        }
    }
}
int t,T;
int main()
{
    // freopen("data.in","r",stdin);
    // freopen("right.out","w",stdout);
    cin>>T;
    while(++t<=T)
    {
        printf("Case %d:\n",t);
        solve();
    }
}
posted @ 2020-07-30 23:07  Point_King  阅读(148)  评论(0编辑  收藏  举报