题目链接:约会安排 - HDU 4553 - Virtual Judge (ppsucxtt.cn)
由于题目是中文的,题目大意我就不说了,下面直接说思路:
对于屌丝的邀请,我们不能使用任何已经被占用的时间,而对于女神的邀请我们却可以无视屌丝的邀请,这就意味着他们之间的关系是具有优先级的,我们需要建立两棵线段树,一棵维护女神和屌丝的共同占用时间,另一棵只维护女神的占用时间。对于屌丝的邀请,我们只能在屌丝和女生共用的那棵线段树上查找,而对于女神的邀请我们就可以在两棵树上查找,只是我们要先在屌丝和女生共用的那棵线段树上查找,如果找不到合适时间再从女神独自占有的那棵线段树上查找。对于每次查找,都是寻找一块连续时间,所以我们要记录区间的最大连续未被占用的时间,这显然就是一个区间合并问题,在这里对区间合并方面的细节我就不赘述了,不明白的小伙伴可以看下我之前的博客,现在给出区间合并的博客地址:
(33条消息) LCIS(线段树+区间合并)_AC__dream的博客-CSDN博客
对于查找连续时间我们可以从头开始二分查找,注意左边界一直是1,如果找到了最小右边界,则满足条件的左边界就是右边界-时间长度+1了。最后的操作就是一个区间清空操作,这就是一个简单的置0操作,由于0是一个操作数,所以我们的lazy数组应该初始化为-1,其他的就没什么可说的了,下面上代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> using namespace std; const int N=2e6+10; int l[2][N],r[2][N],head[2][N],tail[2][N],maxx[2][N],lazy[2][N]; //head[i][j]表示第i棵线段树的第j个区间以区间左边界开头的最长连续1的个数 //tail[i][j]表示第i棵线段树的第j个区间以区间右边界结尾的最长连续1的个数 //maxx[i][j]表示第i棵线段树的第j个区间内的最长连续1的个数 void pushup(int k,int id) { if(head[k][id<<1]==r[k][id<<1]-l[k][id<<1]+1) head[k][id]=head[k][id<<1]+head[k][id<<1|1]; else head[k][id]=head[k][id<<1]; if(tail[k][id<<1|1]==r[k][id<<1|1]-l[k][id<<1|1]+1) tail[k][id]=tail[k][id<<1]+tail[k][id<<1|1]; else tail[k][id]=tail[k][id<<1|1]; maxx[k][id]=max(maxx[k][id<<1],maxx[k][id<<1|1]); if(tail[k][id<<1]&&head[k][id<<1|1]) maxx[k][id]=max(maxx[k][id],tail[k][id<<1]+head[k][id<<1|1]); } void pushdown(int k,int id) { if(lazy[k][id]!=-1) { lazy[k][id<<1]=lazy[k][id]; lazy[k][id<<1|1]=lazy[k][id]; maxx[k][id<<1]=head[k][id<<1]=tail[k][id<<1]=(r[k][id<<1]-l[k][id<<1]+1)*lazy[k][id]; maxx[k][id<<1|1]=head[k][id<<1|1]=tail[k][id<<1|1]=(r[k][id<<1|1]-l[k][id<<1|1]+1)*lazy[k][id]; lazy[k][id]=-1; } } void build(int k,int id,int L,int R) { l[k][id]=L;r[k][id]=R;head[k][id]=tail[k][id]=maxx[k][id]=R-L+1;lazy[k][id]=-1; if(L==R) return ; int mid=L+R>>1; build(k,id<<1,L,mid); build(k,id<<1|1,mid+1,R); pushup(k,id); return ; } void update_interval(int k,int id,int L,int R,int val) { if(l[k][id]>=L&&r[k][id]<=R) { lazy[k][id]=val; head[k][id]=tail[k][id]=maxx[k][id]=(r[k][id]-l[k][id]+1)*val; return ; } pushdown(k,id); int mid=l[k][id]+r[k][id]>>1; if(L<=mid) update_interval(k,id<<1,L,R,val); if(mid+1<=R) update_interval(k,id<<1|1,L,R,val); pushup(k,id); } int query_interval(int k,int id,int L,int R) { if(r[k][id]<L||l[k][id]>R) return 0; if(l[k][id]>=L&&r[k][id]<=R) return maxx[k][id]; pushdown(k,id); int mid=l[k][id]+r[k][id]>>1; int ans=max(query_interval(k,id<<1,L,R),query_interval(k,id<<1|1,L,R)); ans=max(ans,min(tail[k][id<<1],r[k][id<<1]-L+1)+min(head[k][id<<1|1],R-l[k][id<<1|1]+1));//防止越界 return ans; } int main() { int T; cin>>T; for(int i=1;i<=T;i++) { int t,n; printf("Case %d:\n",i); scanf("%d%d",&t,&n); build(0,1,1,t);//维护屌丝和女神的线段树 build(1,1,1,t);//维护女神的线段树 while(n--) { char op[20]; int l,r,tt; scanf("%s",op); if(op[0]=='D') { scanf("%d",&tt); //屌丝的邀请只能在屌丝和女神共有的线段树上二分查找 if(query_interval(0,1,1,t)<tt) puts("fly with yourself"); else { int ll=1,rr=t; while(ll<rr) { int mid=ll+rr>>1; if(query_interval(0,1,1,mid)>=tt) rr=mid; else ll=mid+1; } printf("%d,let's fly\n",ll-tt+1); update_interval(0,1,ll-tt+1,ll,0); } } else if(op[0]=='N') { scanf("%d",&tt); //女神的邀请可以在两棵线段树上二分查找,先查屌丝和女神共有的线段树 if(query_interval(0,1,1,t)>=tt) { int ll=1,rr=t; while(ll<rr) { int mid=ll+rr>>1; if(query_interval(0,1,1,mid)>=tt) rr=mid; else ll=mid+1; } printf("%d,don't put my gezi\n",ll-tt+1); update_interval(0,1,ll-tt+1,ll,0); update_interval(1,1,ll-tt+1,ll,0); } else if(query_interval(1,1,1,t)>=tt) { int ll=1,rr=t; while(ll<rr) { int mid=ll+rr>>1; if(query_interval(1,1,1,mid)>=tt) rr=mid; else ll=mid+1; } printf("%d,don't put my gezi\n",ll-tt+1); //将两棵线段树对应位置都填满 update_interval(0,1,ll-tt+1,ll,0); update_interval(1,1,ll-tt+1,ll,0); } else puts("wait for me"); } else { scanf("%d%d",&l,&r); //将两棵线段树对应位置都清空 update_interval(0,1,l,r,1); update_interval(1,1,l,r,1); puts("I am the hope of chinese chengxuyuan!!"); } } } return 0; }