这题情况真是很多,而且我看这题写题解的人不多,所以来写一下这个题
首先讲一下这个题的思路:
- 用一棵线段树来维护空闲区间的信息(起始点,长度)
- 再用另一颗线段树来维护车队信息(起始点,长度)
这个思路是从这个大佬的称述和代码中得到的.
然后我又简化了情况之后最后只有3类情况需要考虑
- 整段区间没有车队
- 需要插入的是中间区间
- 需要插入的是最后区间
只有一种情况会被归到第一类情况:没有车队的情况(PrevFree>m&&mcnt1==2)
有两种情况会被归到第二类情况:第一个车队前的空位有足够空间(PrevFree>m)
或者查询到的空闲区间不是最后区间(pos!=INF&&pos+len!=n+1)
也有两种情况会被归到第三类情况:查询到的空闲区间是最后区间(pos!=INF&&pos+len==n+1)
或者最后车队后面的空位有足够空间(pos==INF&&len>=m)
话不多说,上代码(zkw线段树版):
#include<stdio.h>
#include<string.h>
#include<set>
#include<map>
const int INF=0x3F3F3F3F,INSERT=1,DELETE=0;
std::set<int>s[50005];std::map<int,int>flen;
int M,N,x,w,mcnt[1<<17],mlen[50005],fpos[1<<18];
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
void Fupdate(int pos,int len,int mode){
if(len<=0)return;flen[pos]=len;
if(mode)s[len].insert(pos);else s[len].erase(pos);
fpos[len+N]=s[len].empty()?INF:*s[len].begin();
for(len=len+N>>1;len;len/=2)
fpos[len]=min(fpos[len*2],fpos[len*2+1]);
}
int Fquery(int l,int r){
for(x=INF,l+=N-1,r+=N+1;l^r^1;l/=2,r/=2){
if(~l&1)x=min(x,fpos[l^1]);
if( r&1)x=min(x,fpos[r^1]);
}return x;
}
void Mupdate(int pos,int len,int mode){
mlen[pos]=len*mode;pos++;mcnt[pos+=M]=mode;
for(pos/=2;pos;pos/=2)mcnt[pos]=mcnt[pos*2]+mcnt[pos*2+1];
}
int Mquery(int rank){
for(x=1;x<M;)
if(rank<=mcnt[x*2])x=x*2;
else rank-=mcnt[x*2],x=x*2+1;
return x-M-1;
}
/*nc*/inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
/*cini*/int ch,res;
int cini(){
while((ch=nc())<'0'||ch>'9');res=ch-'0';
while((ch=nc())>='0'&&ch<='9')res=res*10+ch-'0';
return res;
}
int main(){
int T=cini();
for(int kase=1;kase<=T;kase++){
printf("Case #%d:\n",kase);
int n=cini(),q=cini();
M=1;while(M<n+4)M*=2;
N=1;while(N<n+2)N*=2;
for(int i=0;i<50005;i++)
if(!s[i].empty())s[i].clear();
memset(fpos,0x3F,sizeof fpos);
memset(mcnt,0x00,sizeof mcnt);
memset(mlen,0x00,sizeof mlen);
flen.clear();flen[INF]=INF;
Fupdate(1-0,n,INSERT);
Mupdate(1-1,1,INSERT);
Mupdate(n+1,1,INSERT);
while(q--){
if(nc()=='A'){
int PrevFree,LastFree,ans;
int m=cini(),l=cini(),r=cini();
if(m>n){puts("-1");continue;}
PrevFree=Mquery(2);
LastFree=Mquery(mcnt[1]-1);
LastFree=n+1-LastFree-mlen[LastFree];
int pos=Fquery(m,min(n,m+l+r)),len=flen[pos];
if(PrevFree>m&&mcnt[1]==2){
Fupdate(1,PrevFree-1,DELETE);
Mupdate(ans=1,m,INSERT);
Fupdate(m+1,n-m,INSERT);
}else if(PrevFree>m||(pos!=INF&&pos+len!=n+1)){
if(PrevFree>m)pos=1,len=PrevFree-1;
if(len>l+m+r)ans=-1;
else{
Fupdate(pos,len,DELETE);
Mupdate(ans=pos+max(0,len-r-m),m,INSERT);
Fupdate(pos,ans-pos,INSERT);
Fupdate(ans+m,pos+len-ans-m,INSERT);
}
}else{
if(pos==INF)len=LastFree,pos=n+1-len;
if(len<m)ans=-1;
else{
Fupdate(pos,len,DELETE);
Mupdate(ans=pos,m,INSERT);
}
}
printf("%d\n",ans);
}else{
int k=cini()+1;
if(k<=0||k>=mcnt[1])continue;
int last=Mquery(k-1),curr=Mquery(k+0),next=Mquery(k+1);
w=last+mlen[last];Fupdate(w,curr-w,DELETE);
w=curr+mlen[curr];Fupdate(w,next-w,DELETE);
w=last+mlen[last];Fupdate(w,next-w,INSERT);
Mupdate(curr,mlen[curr],DELETE);
}
}
}
return 0;
}
递归版是我从dalao的代码中化简得到的,原来的代码在上面的传送门里:
有很多参数调整,变量名调整.为了更易读吧…
#include<bits/stdc++.h>
using namespace std;
const int MAXN=51000 + 1000;
const int INF = 0x3f3f3f3f;
const int INSERT=1;
const int DELETE=0;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (L+R>>1)
#define lson L,mid,ls
#define rson mid+1,R,rs
struct TreeNode{
int pos,len;
}FreeInterval[MAXN<<2],CadeRank[MAXN<<2];
set<int>s[MAXN];
int n;
void FreeInterval_build(int L=1,int R=n,int rt=1){
if(L==R){
s[L].clear();
FreeInterval[rt].pos=INF;
FreeInterval[rt].len=L;
return ;
}
FreeInterval_build(lson);
FreeInterval_build(rson);
FreeInterval[rt]=FreeInterval[rt*2];
}
void FreeInterval_update(int pos,int len,int flag,int L=1,int R=n,int rt=1){
if(L==R){
if(flag){
s[L].insert(pos);
FreeInterval[rt].pos=*s[L].begin();
}else{
s[L].erase(pos);
FreeInterval[rt].pos=INF;
if(!s[L].empty())
FreeInterval[rt].pos=*s[L].begin();
}
FreeInterval[rt].len=L;
return ;
}
if(len<=mid)
FreeInterval_update(pos,len,flag,lson);
else
FreeInterval_update(pos,len,flag,rson);
FreeInterval[rt]=FreeInterval[rt*2+(FreeInterval[ls].pos>FreeInterval[rs].pos)];
}
TreeNode FreeInterval_query(int l,int r,int L=1,int R=n,int rt=1){
if(l<=L&&R<=r)return FreeInterval[rt];
TreeNode t1,t2;t1.pos=INF;t2.pos=INF;
if(l<=mid)t1=FreeInterval_query(l,r,lson);
if(r> mid)t2=FreeInterval_query(l,r,rson);
return t1.pos<t2.pos?t1:t2;
}
void CadeRank_update(int pos,int len,int flag,int L=0,int R=n+1,int rt=1){
if(L==R){
CadeRank[rt].pos=flag;
CadeRank[rt].len=len*flag;
return ;
}
if(pos<=mid)CadeRank_update(pos,len,flag,lson);
else CadeRank_update(pos,len,flag,rson);
CadeRank[rt].pos=CadeRank[ls].pos+CadeRank[rs].pos;
}
void CadeRank_query(int rank,int &pos,int &len,int L=0,int R=n+1,int rt=1){
if(L==R){
pos=L;
len=CadeRank[rt].len;
return ;
}
if(rank<=CadeRank[ls].pos)
CadeRank_query(rank,pos,len,lson);
else
CadeRank_query(rank-CadeRank[ls].pos,pos,len,rson);
}
int main(){
int t,cas=0,q;
scanf("%d",&t);
while(t--){
printf("Case #%d:\n",++cas);
scanf("%d %d",&n,&q);
FreeInterval_build();
memset(CadeRank,0,sizeof CadeRank);
FreeInterval_update(1,n,INSERT);
CadeRank_update(0,1,INSERT);
CadeRank_update(n+1,1,INSERT);
int PrevFree=n,LastFree=n;
char ch;
int mi,li,ri,k;
int where,len,ans;
for(int i=0;i<q;i++){
scanf(" %c",&ch);
if(ch=='A'){//TRY TO INSERT A MOTORCADE LENGTH IS MI,CONSTRAINT IS LI&RI
scanf("%d%d%d",&mi,&li,&ri);
if(PrevFree>=mi){//ABLE TO INSERT INTO TOTAL'S BEGIN
FreeInterval_update(1,PrevFree,DELETE);
if(PrevFree==n){//NO MOTORCADE
if(n-mi>0)//HAVE FREE INTERVAL(AFTER)
FreeInterval_update(mi+1,n-mi,INSERT);//POS IS MI+1,LEN IS N-MI
CadeRank_update(1,mi,INSERT);//THERE IS A MOTORCADE POS IS 1,LEN IS MI
PrevFree=0;//PREFREEPOS IS 0
LastFree=n-mi;//FINALCADEPOS IS N-MI
ans=1;//ANS IS 1(TOTAL'S BEGIN)
}else{//EXIST MOTORCADE
//BECAUSE WILL INSERT INTO TOTAL'S BEGIN ,SO NOT CONSIDER LI
if(PrevFree>=mi+ri){//MUST HAVE FREE INTERVAL(BETWEEN),BUT NEED CALC 'WHERE' BECAUSE OF CONSTRAINT
where=PrevFree-ri+1;//FREE INTERVAL START POSITION
len=ri;//LENGTH IS RI
FreeInterval_update(where,len,INSERT);//UPDATE FREE INTERVAL
CadeRank_update(where-mi,mi,INSERT);//NEW MOTORCADE POSITION IS PREFREEPOS+1-RI-MI,LENGTH MUST IS MI
ans=where-mi;//ANS IS PREFREEPOS+1-RI-MI
PrevFree=PrevFree-mi-ri;//UPDATE PREFREEPOS
if(PrevFree)//IF PREFREEPOS IS 0,MEANING THERE IS NO FREE INTERVAL AT TOTAL'S BEGIN
FreeInterval_update(1,PrevFree,INSERT);//INSERT A FREE INTERVAL INTO TOTAL'S BEGIN
}else{//BECAUSE OF CONSTRAINT,POS MUST IS 0,SO NO FREE INTERVAL(BEFORE)
len=PrevFree-mi;//LENGTH OF GAP BETWEEN NEED_INSERT_MOTORCADE AND NEXT_MOTORCADE
if(len)//IF LEN!=0,THAT IS MEANING HAVE FREE INTERVAL
FreeInterval_update(mi+1,len,INSERT);
CadeRank_update(1,mi,INSERT);//THERE IS A MOTORCADE POS IS 1,LEN IS MI
ans=1;//ANS MUST IS 1(TOTAL'S BEGIN)
PrevFree=0;//PREFREEPOS IS 0
}
}
}else{//CONSIDER OTHER POSITION EXCEPT TOTAL'S BEGIN
TreeNode tx=FreeInterval_query(mi,mi+li+ri);//QUERY WHETHER THERE HAVE LENGTH IN RANGE(MI,MI+LI+RI)
if(tx.pos==INF){//NO QUERYED FREE INTERVAL IN MIDDLE
if(LastFree>=mi){//IF CAN INSERT AFTER
FreeInterval_update(n-LastFree+1,LastFree,DELETE);//FIRST DELETE FINAL FREE INTERVAL
where=n-(LastFree-mi)+1;//NEW FREE INTERVAL START POSITION
len=LastFree-mi;//NEW FREE INTERVAL LENGTH
LastFree-=mi;//UPDATE FINALCADEPOS,DECREASE MI
if(len)//IF THERE HAVE ROOM TO BE INSERTED A FREE INTERVAL
FreeInterval_update(where,len,INSERT);
CadeRank_update(where-mi,mi,INSERT);//INSERT A NEW MOTORCADE
ans=where-mi;//ANS IS WHERE-MI
}
else
ans=-1;//CAN'T INSERT ANYWHERE
}else{//GET A QUERYED FREE INTERVAL IN MIDDLE
FreeInterval_update(tx.pos,tx.len,DELETE);//AT FIRST,DELETE GOT INTERVAL
if(tx.pos+tx.len-1==n){//GOT INTERVAL IS FINAL INTERVAL
ans=tx.pos;
LastFree=len=LastFree-mi;
if(len)
FreeInterval_update(tx.pos+mi,len,INSERT);
CadeRank_update(tx.pos,mi,INSERT);
}else if(tx.len>=mi+ri){//MUST KEEP DISTANCE BETWEEN LAST_CADE
len=tx.len-(mi+ri);//NEW FREE INTERVAL(BETWEEN LAST_CADE)
if(len)//IF EXIST
FreeInterval_update(tx.pos,len,INSERT);
FreeInterval_update(tx.pos+len+mi,ri,INSERT);//NEW FREE INTERVAL(BETWEEN NEXT_CADE)
CadeRank_update(tx.pos+len,mi,INSERT);//INSERT A NEW MOTORCADE
ans=tx.pos+len;//ANS
}else{//NO NEED KEEP DISTANCE BETWEEN LAST_CADE
len=tx.len-mi;//NEW FREE INTERVAL(BETWEEN NEXT_CADE)
if(len)//IF EXIST
FreeInterval_update(tx.pos+mi,len,INSERT);
CadeRank_update(tx.pos,mi,INSERT);//INSERT A NEW MOTORCADE
ans=tx.pos;//ANS
}
}
}
printf("%d\n",ans);//PRINT ANS
}else{//TRY TO DELETE K-TH MOTORCADE
scanf("%d",&k);++k;
int where1,len1,where2,len2,where3,len3;
if(k<CadeRank[1].pos){
CadeRank_query(k-1,where1,len1);//QUERY LAST MOTORCADE
CadeRank_query(k,where2,len2);//QUERY NEED MOTORCADE
CadeRank_query(k+1,where3,len3);//QUERY NEXT MOTORCADE
CadeRank_update(where2,len2,DELETE);//DELETE NEED MOTORCADE
len=where2-(where1+len1);//IF THERE IS GAP BETWEEN LAST AND NEED
if(len>0)
FreeInterval_update(where1+len1,len,DELETE);
len=where3-(where2+len2);//GAP BETWEEN NEED AND NEXT
if(len>0)
FreeInterval_update(where2+len2,len,DELETE);
len=where3-(where1+len1);//EMMMM...THIS LEN SHOULD MUST BIGGER THAN 0
if(len>0)
FreeInterval_update(where1+len1,len,INSERT);//INSERT A NEW INTERVAL
if(where1==0)//IF NOW MOTORCADE IS FIRST LEGAL MOTORCADE(AND BE DELETED)
PrevFree=len;//NEED TO UPDATE PREFREEPOS
if(where3==n+1)//IF NOW MOTORCADE IS LAST LEGAL MOTORCADE(AND BE DELETED)
LastFree=len;//NEED TO UPDATE FINALCADEPOS
}
}
}
}
return 0;
}
真的崩溃了,为什么同样的代码C++能过G++不能过,有的是G++能过C++不能,超诡异的…
用nc优化的话能快但是只能上C++,不用的话只能上G++