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\),分别为以左边界为一端的最长串长度,以右边界为一端的最长串长度,该区间的最长串长度,该区间最长串的左边界。
根据变量的定义,我们可以轻易得出状态转移方程:
代码如下:
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();
}
}