考虑n=1的做法,就是支持:
1.在线删一个数
2.在结尾加一个数
3.查询序列的第y个数
用线段树记录区间内被删元素的个数,可以通过线段树上二分快速得解,对于新增的数,用vector记录即可。
对于满分同样如此,对每行开一个线段树,再对最后一列单独开一个。
对于每次操作:
若在最后一列:就是对最后一列直接使用n=1的做法。
若不在:对第x列的前m-1个用n=1的做法,再将最后一列的第x个加入第x列的末尾,然后再对最后一列使用n=1的做法。
1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 #define lson ls[x],L,mid 5 #define rson rs[x],mid+1,R 6 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 7 typedef long long ll; 8 using namespace std; 9 10 const int N=300010,M=N*40; 11 ll ans; 12 int n,m,Q,mx,x,y,nd,rt[N],sm[M],ls[M],rs[M]; 13 vector<ll>V[N]; 14 15 void ins(int &x,int L,int R,int pos){ 16 if (!x) x=++nd; 17 if (L==R){ sm[x]++; return; } 18 int mid=(L+R)>>1; 19 if (pos<=mid) ins(lson,pos); else ins(rson,pos); 20 sm[x]=sm[ls[x]]+sm[rs[x]]; 21 } 22 23 int que(int x,int L,int R,int pos){ 24 if (L==R) return L; 25 int mid=(L+R)>>1,t=mid-L+1-sm[ls[x]]; 26 if (t>=pos) return que(lson,pos); else return que(rson,pos-t); 27 } 28 29 int main(){ 30 scanf("%d%d%d",&n,&m,&Q); mx=max(n,m)+Q; 31 rep(i,0,n) V[i].push_back(0); 32 while (Q--){ 33 scanf("%d %d",&x,&y); 34 if (y==m){ 35 int s=que(rt[0],1,mx,x); 36 if (s<=n) ans=1ll*s*m; else ans=V[0][s-n]; 37 printf("%lld\n",ans); ins(rt[0],1,mx,s); V[0].push_back(ans); 38 continue; 39 } 40 int t=que(rt[x],1,mx,y); 41 if (t<m) ans=1ll*(x-1)*m+t; else ans=V[x][t-(m-1)]; 42 printf("%lld\n",ans); ins(rt[x],1,mx,t); 43 int s=que(rt[0],1,mx,x); ll tmp=ans; 44 if (s<=n) ans=1ll*s*m; else ans=V[0][s-n]; 45 V[x].push_back(ans); ins(rt[0],1,mx,s); V[0].push_back(tmp); 46 } 47 return 0; 48 }