[NOIP2017]列队(线段树)

时间:2021-09-07 20:47:14

考虑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 }