双线段树+区间合并
sum保存最大区间长度,lsum保存邻接左边界最大区间长度,rsum则是右边界
合并时可以通过这些计算出父节点的值
对于屌丝的邀请和女神的邀请可以安排两个线段树来查询时间
详见代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=100000+10; //数组大小
int dsum[maxn<<2],dlsum[maxn<<2],drsum[maxn<<2]; //屌丝树
int nsum[maxn<<2],nlsum[maxn<<2],nrsum[maxn<<2]; //女神树
int lazy[maxn<<2];
void PushUp(int rt,int l,int r)
{
if(l==r) return;
int m=(l+r)>>1;
dlsum[rt]=dlsum[rt<<1];
drsum[rt]=drsum[rt<<1|1];
if(dlsum[rt<<1]==m-l+1) dlsum[rt]+=dlsum[rt<<1|1];
if(drsum[rt<<1|1]==r-m) drsum[rt]+=drsum[rt<<1];
dsum[rt]=max(drsum[rt<<1]+dlsum[rt<<1|1],max(dsum[rt<<1],dsum[rt<<1|1]));
nlsum[rt]=nlsum[rt<<1];
nrsum[rt]=nrsum[rt<<1|1];
if(nlsum[rt<<1]==m-l+1) nlsum[rt]+=nlsum[rt<<1|1];
if(nrsum[rt<<1|1]==r-m) nrsum[rt]+=nrsum[rt<<1];
nsum[rt]=max(nrsum[rt<<1]+nlsum[rt<<1|1],max(nsum[rt<<1],nsum[rt<<1|1]));
}
void PushDown(int rt,int l,int r)
{
if(l==r) return;
if(lazy[rt]!=0)
{
int m=(l+r)>>1;
lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
if(lazy[rt]==-1)
{
dsum[rt<<1]=dlsum[rt<<1]=drsum[rt<<1]=m-l+1;
dsum[rt<<1|1]=dlsum[rt<<1|1]=drsum[rt<<1|1]=r-m;
nsum[rt<<1]=nlsum[rt<<1]=nrsum[rt<<1]=m-l+1;
nsum[rt<<1|1]=nlsum[rt<<1|1]=nrsum[rt<<1|1]=r-m;
}
else
{
dsum[rt<<1]=dlsum[rt<<1]=drsum[rt<<1]=0;
dsum[rt<<1|1]=dlsum[rt<<1|1]=drsum[rt<<1|1]=0;
if(lazy[rt]==2)
{
nsum[rt<<1]=nlsum[rt<<1]=nrsum[rt<<1]=0;
nsum[rt<<1|1]=nlsum[rt<<1|1]=nrsum[rt<<1|1]=0;
}
else
{
nsum[rt<<1]=nlsum[rt<<1]=nrsum[rt<<1]=m-l+1;
nsum[rt<<1|1]=nlsum[rt<<1|1]=nrsum[rt<<1|1]=r-m;
}
}
lazy[rt]=0;
}
}
void build(int l,int r,int rt)
{
lazy[rt]=0;
if(l==r)
{
dsum[rt]=dlsum[rt]=drsum[rt]=1;
nsum[rt]=nlsum[rt]=nrsum[rt]=1;
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
PushUp(rt,l,r);
}
void update(int L,int R,int f,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
if(f!=-1)
{
dsum[rt]=dlsum[rt]=drsum[rt]=0;
if(f==2) nsum[rt]=nlsum[rt]=nrsum[rt]=0;
else nsum[rt]=nlsum[rt]=nrsum[rt]=r-l+1;
}
else
{
dsum[rt]=dlsum[rt]=drsum[rt]=r-l+1;
nsum[rt]=nlsum[rt]=nrsum[rt]=r-l+1;
}
lazy[rt]=f;
return;
}
if(l==r) return;
PushDown(rt,l,r);
int m=(l+r)>>1;
if(L<=m) update(L,R,f,l,m,rt<<1);
if(R>m) update(L,R,f,m+1,r,rt<<1|1);
PushUp(rt,l,r);
}
int query_d(int len,int l,int r,int rt)
{
if(l==r) return l;
PushDown(rt,l,r);
int m=(l+r)>>1;
if(dsum[rt<<1]>=len) return query_d(len,l,m,rt<<1);
else if(drsum[rt<<1]+dlsum[rt<<1|1]>=len) return m-drsum[rt<<1]+1;
else return query_d(len,m+1,r,rt<<1|1);
}
int query_n(int len,int l,int r,int rt)
{
if(l==r) return l;
PushDown(rt,l,r);
int m=(l+r)>>1;
if(nsum[rt<<1]>=len) return query_n(len,l,m,rt<<1);
else if(nrsum[rt<<1]+nlsum[rt<<1|1]>=len) return m-nrsum[rt<<1]+1;
else return query_n(len,m+1,r,rt<<1|1);
}
int main()
{
//freopen("/home/zlwang/test.txt","r",stdin);
int T,n,m,kase=0;
int a,b,ans;
char s[10];
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
build(1,n,1);
printf("Case %d:\n",++kase);
for(int i=0;i<m;i++)
{
scanf("%s",s);
if(s[0]=='D')
{
scanf("%d",&a);
if(dsum[1]>=a)
{
ans=query_d(a,1,n,1);
printf("%d,let's fly\n",ans);
update(ans,ans+a-1,1,1,n,1);
}
else printf("fly with yourself\n");
}
else if(s[0]=='N')
{
scanf("%d",&a);
if(dsum[1]>=a)
{
ans=query_d(a,1,n,1);
printf("%d,don't put my gezi\n",ans);
update(ans,ans+a-1,2,1,n,1);
}
else if(nsum[1]>=a)
{
ans=query_n(a,1,n,1);
printf("%d,don't put my gezi\n",ans);
update(ans,ans+a-1,2,1,n,1);
}
else printf("wait for me\n");
}
else
{
scanf("%d%d",&a,&b);
update(a,b,-1,1,n,1);
printf("I am the hope of chinese chengxuyuan!!\n");
}
}
}
return 0;
}