离线维护 支持插入数 的序列
论离线维护插入单点
碰到过好多类似的题,都在维护这个序列中卡住了,这是个简单易懂\(O(n log^2_2n)\)
我们考虑从后往前维护序列
对于第n个插入的数,它最后所在的位置p就是预期位置
然后原本在p后面的数就会集体往后移一位,我们用树状数组维护要往后移几位
例题
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
const int N=4e5+5;
int n,cnt,m,t[N<<2];
vector<int>vec[N];
vector<pii>que[N];
int ans[N],c[N];
void add(int x,int y){for(;x<=m;x+=x&-x)c[x]+=y;}
int ask(int x){int res=0;for(;x;x&=x-1)res+=c[x];return res;}
void change(int k,int l,int r,int x){
if(l==r){t[k]++;return;}
int mid=l+r>>1;
if(x<=mid)change(k*2,l,mid,x);
else change(k*2+1,mid+1,r,x);
t[k]=t[k*2]+t[k*2+1];
}
int ask(int x,int l,int r,int L,int R){
if(L>R)return 0;
if(l>=L&&r<=R)return t[x];
int mid=(l+r)>>1,rec=0;
if(mid>=L)rec=ask(x<<1,l,mid,L,R);
if(mid+1<=R)rec+=ask(x<<1|1,mid+1,r,L,R);
return rec;
}
int main(){
freopen("queue.in","r",stdin);
freopen("queue.out","w",stdout);
scanf("%d",&n);
for(int i=1,c,v;i<=n;i++){
scanf("%d%d",&c,&v);
int pos,id;
if(vec[c].empty()||ask(1,1,n,vec[c].back()+1,cnt)>v)change(1,1,n,++cnt),vec[c].push_back(cnt),pos=cnt,id=0;
else{
int l=0,r=vec[c].size()-1;
while(l<r){
int mid=(l+r)>>1;
if(ask(1,1,n,vec[c][mid]+1,cnt)<=v)r=mid;
else l=mid+1;
}
pos=vec[c][l];
id=ask(1,1,n,vec[c][l],vec[c][l])-min(ask(1,1,n,vec[c][l],vec[c][l]),v-ask(1,1,n,vec[c][l]+1,cnt));
change(1,1,n,vec[c][l]);
}
que[pos].push_back(make_pair(id,i));
}
for(int i=1;i<=cnt;i++){
m=que[i].size();
for(int j=1;j<=m;j++)c[j]=0,ans[j]=0;
for(int j=1;j<=m;j++)add(j,1);
for(int j=m-1;j>=0;j--){
int x=que[i][j].first;
int l=1,r=m;
while(l<r){
int mid=l+r+1>>1;
if(ask(mid-1)<=x)l=mid;
else r=mid-1;
}
ans[l]=que[i][j].second;
add(l,-1);
}
for(int j=1;j<=m;j++)printf("%d ",ans[j]);
}
puts("");
return 0;
}