*原题链接*
本题与NOIP2017列队有很多共通之处,都是一开始给我们一个排好编号的队列,然后进行一些操作。
如果n的范围不大,我们会如何做呢?很容易想到权值线段树,以编号为下标建立权值线段树,维护每个下标上有多少数,接下来的操作就很容易了。
但本题n过于大,不过我们很容易发现,初始状态很容易计算,所以只需要设法维护操作后的状态。例如此题,有编号和排名,我们就可以用两个map维护编号为x的排名,排名为x的编号。
对于权值线段树,我们采用动态开点的技巧,并且不去具体维护有多少个数,而是维护移动过多少个数,这样就避免MLE和TLE。
时间复杂度,空间复杂度
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10,INF=1e8+N;
//fast read,fast write
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
void print(int x){
write(x),cout<<endl;
}
int n,m,root,idx,la,ls[N],rs[N],sum[N],L,R;
map<int,int> id,id2;
void modify(int &u,int x,int l,int r){
if(!u) u=++idx;sum[u]++;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) modify(ls[u],x,l,mid);
else modify(rs[u],x,mid+1,r);
}
int query(int u,int x,int l,int r){
if(!sum[u]||l==r) return 0;
int mid=(l+r)>>1;
if(x<=mid) return query(ls[u],x,l,mid);
return query(rs[u],x,mid+1,r)+sum[ls[u]];
}
int findkth(int u,int k,int l,int r){
if(l==r) return l;
int mid=(l+r)>>1,res=max(0,min(R,mid)-max(L,l)+1-sum[ls[u]]);
if(k<=res) return findkth(ls[u],k,l,mid);
return findkth(rs[u],k-res,mid+1,r);
}
void change(int x,int y){
int pos=(id.find(x)==id.end())?x:id[x];
la=pos-L+1-query(root,pos,-INF,INF),id[y]=pos,id2[pos]=y;
}
void work1(int x){
int pos=(id.find(x)==id.end())?x:id[x];
la=pos-L+1-query(root,pos,-INF,INF),modify(root,pos,-INF,INF);
id[x]=--L,id2[L]=x;
}
void work2(int x){
int pos=(id.find(x)==id.end())?x:id[x];
la=pos-L+1-query(root,pos,-INF,INF),modify(root,pos,-INF,INF);
id[x]=++R,id2[R]=x;
}
void ask(int k){
la=findkth(root,k,-INF,INF),la=(id2.find(la)==id2.end())?la:id2[la];
}
int main(){
n=read(),m=read(),L=1,R=n;
while(m--){
int opt=read(),x,y;
if(opt==1){
x=read(),y=read(),x-=la,y-=la;
change(x,y),print(la);
}
else if(opt==2) x=read(),work1(x-la),print(la);
else if(opt==3) x=read(),work2(x-la),print(la);
else x=read(),ask(x-la),print(la);
}
return 0;
}