【NOIP题解】NOIP2017 TG D2T3 列队
列队,NOIP2017 TG D2T3。
树状数组经典题。
题目链接:洛谷。
题意:
Sylvia 是一个热爱学习的女孩子。
前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。
Sylvia 所在的方阵中有\(n \times m\)名学生,方阵的行数为 \(n\),列数为 \(m\)。
为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 \(1\) 到 \(n \times m\) 编上了号码(参见后面的样例)。即:初始时,第 \(i\) 行第 \(j\) 列 的学生的编号是\((i-1)\times m + j\)。
然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 \(q\) 件这样的离队事件。每一次离队事件可以用数对\((x,y) (1 \leq x \leq n, 1 \leq y \leq m)\)描述,表示第 \(x\) 行第 \(y\) 列的学生离队。
在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:
向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 \(x\) 行第 \(m\) 列。
向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 \(n\) 行第 \(m\) 列。
教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 \(n\) 行 第 \(m\) 列一个空位,这时这个学生会自然地填补到这个位置。
因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少。
注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。
题解:
注意到这个方阵被分成了最右侧一列,左侧\(m-1\)列的每一行,共\(n\)行这\(n+1\)个序列。
操作的本质是:每次从其中一个序列中删除一个值,然后在一个序列中加入一个值。
考虑前50%的部分分:
q是非常小的,我们发现可以把与\(x_i\)无关的行排除掉,因为这些行根本不会有操作。
然后维护每行和最后一列即可。
那么前80%呢?
前50%见上文。下面是后30%
注意到所有的操作只在第一行。
我们考虑把第一行和最后一列并在一起,形成新的序列。
这个序列要支持:删除第\(k\)个元素,在末尾加入元素。
可以使用平衡树实现,但是NOIP不考啊?
考虑用树状数组做?怎么做?树状数组维护这一位有没有元素,\(0\)就是没有,\(1\)就是有。
第\(k\)位就是前缀和等于\(k\)。
删除就是\(1\to 0\)。
添加就是\(0\to 1\),特别的,在末尾添加只要记一个末尾的指针就好了。
怎么找第k位?
树状数组上二分,\(O(log n)\)。
那么100%的数据呢?
发现这个矩阵开始的每一位都确定。
如果我们不维护每一行原来的元素,而是维护新加进来的元素呢?
新加进来的元素总数不会超过\(q\)。
而原来的元素可以直接得到。对于每一行,开一个树状数组来维护答案即可。
这个做法要求离线做,先对所有询问按照\(x_i\)排序,然后按照60%~80%的方法维护。
最后把每行的树状数组(合起来不超过\(q\)个元素),和最后一列的放在一起维护就好了。
时间复杂度\(O(qlog(q)+qlog(m+n+q))\)。
我的代码使用了指针来指向多棵树状数组,是洛谷跑的最快的!1488ms!
代码如下:
1 #pragma GCC optimize("O2") 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define F(i,a,b) for(int i=a;i<=b;++i) 6 #define dF(i,a,b) for(int i=a;i>=b;--i) 7 #define F2(i,a,b) for(int i=a;i<b;++i) 8 #define getchar() (SS==TT&&(TT=(SS=BB)+fread(BB,1,1<<15,stdin),TT==SS)?EOF:*SS++) 9 #define RR register 10 char BB[1<<15],*SS=BB,*TT=BB; 11 inline int read(){ 12 RR int x;RR bool f;RR char c; 13 for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-'); 14 for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0'); 15 return f?-x:x; 16 } 17 using namespace std; 18 int q,I[300010]; 19 long long n,m,a[300010],b[300010]; 20 inline bool cmp(int p1,int p2){return a[p1]==a[p2]?p1<p2:a[p1]<a[p2];} 21 int h[300010],len[300010],len2[300010],bit[900010]; 22 long long arr[900010]; 23 long long Ans[300010]; 24 inline void Ins(int*array,int siz,int i,int x){for(;i<=siz;array[i]+=x,i+=i&-i);} 25 inline int binary(int*array,int siz,int x){ 26 int l=1,r,mid,sum,ans; 27 while(l<=siz&&array[l]<x) l<<=1, ans=l; 28 r=l; sum=array[l>>=1]; 29 while(l<r-1){ 30 mid=l+r>>1; 31 if(mid>siz||array[mid]+sum>=x) r=mid, ans=mid; 32 else l=mid, sum+=array[l]; 33 } ans=r; 34 return ans; 35 } 36 int stk[300001],top; 37 int main(){ 38 n=read(), m=read(), q=read(); 39 F(i,1,q) a[i]=read(), b[i]=read(), I[i]=i; 40 sort(I+1,I+q+1,cmp); 41 F(i,1,m-1) Ins(bit,m-1,i,1); 42 F(i,1,n) len[i]=m-1; 43 F(i,1,q){ 44 if(a[I[i-1]]!=a[I[i]]) 45 while(top) Ins(bit,m-1,stk[top--],1); 46 if(b[I[i]]>len[a[I[i]]]) continue; 47 int pos=binary(bit,m-1,b[I[i]]); 48 Ans[I[i]]=(a[I[i]]-1)*m+pos; 49 Ins(bit,m-1,pos,-1); 50 stk[++top]=pos; 51 --len[a[I[i]]]; 52 } 53 int iter=0; 54 F(i,1,n){ 55 while(iter<=q&&a[I[iter]]<i) ++iter; 56 h[i]=iter-1; 57 } 58 h[n+1]=q; 59 memset(bit,0,sizeof bit); 60 F(i,1,n) len[i]=0, len2[i]=m-1; len[n+1]=n; 61 F(i,1,n) Ins(bit+h[n+1],n+q,i,1), arr[q+i]=i*m; 62 F(i,1,q){ 63 if(Ans[i]){ 64 int pos=binary(bit+h[n+1],n+q,a[i]); 65 Ins(bit+h[n+1],n+q,pos,-1); 66 Ins(bit+h[n+1],n+q,++len[n+1],1); 67 arr[h[n+1]+len[n+1]]=Ans[i]; 68 Ins(bit+h[a[i]],h[a[i]+1]-h[a[i]],++len[a[i]],1); 69 arr[h[a[i]]+len[a[i]]]=arr[h[n+1]+pos]; 70 --len2[a[i]]; 71 } 72 else{ 73 int pos=binary(bit+h[n+1],n+q,a[i]); 74 Ins(bit+h[n+1],n+q,pos,-1); 75 Ins(bit+h[n+1],n+q,++len[n+1],1); 76 if(b[i]!=m){ 77 int pos2=binary(bit+h[a[i]],h[a[i]+1]-h[a[i]],b[i]-len2[a[i]]); 78 Ins(bit+h[a[i]],h[a[i]+1]-h[a[i]],pos2,-1); 79 Ans[i]=arr[h[a[i]]+pos2]; 80 Ins(bit+h[a[i]],h[a[i]+1]-h[a[i]],++len[a[i]],1); 81 arr[h[a[i]]+len[a[i]]]=arr[h[n+1]+pos]; 82 } else Ans[i]=arr[h[n+1]+pos]; 83 arr[h[n+1]+len[n+1]]=Ans[i]; 84 } 85 } 86 F(i,1,q) printf("%lld\n",Ans[i]); 87 return 0; 88 }