[NOIP2017]列队(线段树/裂点splay)
考虑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 }
或裂点splay,一个点代表一个区间,每次删除某个位置k就将其裂为[l,k-1],k,[k+1,r]三个部分,再删掉k。
模板题。常数较大。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=2000010; 8 int n,m,Q,nd,x,y,ch[N][2],rt[N],f[N]; 9 ll L[N],R[N],len[N]; 10 11 int get(ll l,ll r){ nd++; L[nd]=l; R[nd]=r; len[nd]=r-l+1; return nd; } 12 void upd(int x){ len[x]=len[ch[x][0]]+len[ch[x][1]]+R[x]-L[x]+1; } 13 14 void rot(int &rt,int x){ 15 int y=f[x],z=f[y],w=ch[y][1]==x; 16 if (y==rt) rt=x; else ch[z][ch[z][1]==y]=x; 17 f[x]=z; f[y]=x; f[ch[x][w^1]]=y; 18 ch[y][w]=ch[x][w^1]; ch[x][w^1]=y; upd(y); 19 } 20 21 void splay(int &rt,int x){ 22 while (x!=rt){ 23 int y=f[x],z=f[y]; 24 if (y!=rt) ((ch[z][0]==y) ^ (ch[y][0]==x)) ? rot(rt,x) : rot(rt,y); 25 rot(rt,x); 26 } 27 upd(x); 28 } 29 30 void ins(int &rt,ll k){ 31 int y=get(k,k); 32 if (!rt) { rt=y; return; } 33 int x=rt; while (ch[x][1]) x=ch[x][1]; 34 splay(rt,x); f[y]=x; ch[x][1]=y; upd(x); 35 } 36 37 int split(int &rt,int x,ll k){ 38 k+=L[x]; 39 int y=get(k,R[x]); R[x]=k-1; 40 if (!ch[x][1]) f[y]=x,ch[x][1]=y; 41 else{ 42 int s=ch[x][1]; 43 while (ch[s][0]) s=ch[s][0]; 44 f[y]=s; ch[s][0]=y; 45 } 46 splay(rt,y); return y; 47 } 48 49 int find(int x,ll &k){ 50 if (k<=len[ch[x][0]]) return find(ch[x][0],k); 51 k-=len[ch[x][0]]; 52 if (k<=R[x]-L[x]+1) return x; else return k-=R[x]-L[x]+1,find(ch[x][1],k); 53 } 54 55 ll del(int &rt,ll k){ 56 int x=find(rt,k); 57 if (k<R[x]-L[x]+1) split(rt,x,k); 58 if (k>1) x=split(rt,x,k-1); 59 splay(rt,x); f[ch[x][0]]=f[ch[x][1]]=0; 60 if (!ch[x][0]) rt=ch[x][1]; 61 else{ 62 int y=ch[x][0]; rt=y; 63 while (ch[y][1]) y=ch[y][1]; 64 splay(rt,y); ch[y][1]=ch[x][1]; 65 f[ch[x][1]]=y; upd(y); 66 } 67 return L[x]; 68 } 69 70 int main(){ 71 freopen("phalanx.in","r",stdin); 72 freopen("phalanx.out","w",stdout); 73 scanf("%d%d%d",&n,&m,&Q); 74 rep(i,1,n) rt[i]=++nd,L[i]=(i-1ll)*m+1,R[i]=1ll*i*m-1,len[i]=R[i]-L[i]+1; 75 rep(i,1,n) ins(rt[0],1ll*i*m); 76 while (Q--){ 77 scanf("%d%d",&x,&y); ll ans; 78 ins(rt[x],del(rt[0],x)); 79 printf("%lld\n",ans=del(rt[x],y)); 80 ins(rt[0],ans); 81 } 82 return 0; 83 }