[NOIp 2017]列队

Description

Sylvia 是一个热爱学习的女♂孩子。
前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。
Sylvia 所在的方阵中有n×m名学生,方阵的行数为 n,列数为 m。
为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 n×m 编上了号码(参见后面的样例)。即:初始时,第 iii 行第 jjj 列 的学生的编号是(i−1)×m+j。
然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 q 件这样的离队事件。每一次离队事件可以用数对(x,y)(1≤x≤n,1≤y≤m)描述,表示第 x 行第 y 列的学生离队。
在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:

向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 x 行第 m 列。

向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 n 行第 m 列。
教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 n 行 第 m 列一个空位,这时这个学生会自然地填补到这个位置。
因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少。
注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。

正解:线段树/树状数组/平衡树

转载自http://www.cnblogs.com/Yuzao/p/7920813.html#3867765

\(30\%\):开个 \(n*m\) 的数组模拟即可
\(50\%\):发现只有500行有改动,所以单独拿出这500行和最后一列,模拟即可.
\(80\%\):只有一行的话,我们就开一个 \(m+q\) 的数组,然后树状数组维护每一个位置是否有人,并且维护每一个位置的人的id,这样就会产生很多空位,询问就是查找第 \(y\) 个有人的位置的id,二分+树状数组 或 直接线段树查找第k大即可,与 \(70\) 分不同的是,还需要再维护最后一列,像行一样维护即可
\(100\%\):和 \(80\) 分类似,想到有很多位置根本没有大的变动,我们像之前一样,我们把只需要出队的位置删除即可,所以我们维护每一个位置是否被删,但是不太好存,所以用动态开点线段树标记删除位置,然后像之前一样二分找出第 \(y\) 个有人的位置即可,还有一个不同的是,id数组需要动态维护,所以开个vector存即可,所以100和80的区别仅在于是否使用动态内存.

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 typedef long long lol;
 8 const int N=300000;
 9 int chl[10000005],chr[10000000+5],cnt[10000000+5],root[N+5],tot;
10 vector<lol>G[N+5];
11 lol n,m,sum,q;
12 lol query(int rt,int l,int r,lol k)
13 {
14     if (l==r) return l;
15     int mid=(l+r)/2;
16     if (mid-l+1-cnt[chl[rt]]>=k) return query(chl[rt],l,mid,k);
17     else return query(chr[rt],mid+1,r,k-(mid-l+1-cnt[chl[rt]]));
18 }
19 void del(int &rt,int l,int r,lol k)
20 {
21     if (!rt) rt=++tot;
22     cnt[rt]++;
23     if (l==r) return;
24     int mid=(l+r)/2;
25     if (k<=mid) del(chl[rt],l,mid,k);
26     else del(chr[rt],mid+1,r,k);
27 }
28 lol zyys1(lol x,lol kind)
29 {
30     lol pos=query(root[n+1],1,sum,x);
31     del(root[n+1],1,sum,pos);
32     lol ans=0;
33     if (pos<=n) ans=m*pos;
34     else ans=G[n+1][pos-n-1];
35     if (kind==0) G[n+1].push_back(ans);
36     else G[n+1].push_back(kind);
37     return ans; 
38 }
39 lol zyys2(lol x,lol y)
40 {
41     lol pos=query(root[x],1,sum,y);
42     del(root[x],1,sum,pos);
43     lol ans=0;
44     if (pos<m) ans=(x-1)*m+pos;
45     else ans=G[x][pos-m];
46     G[x].push_back(zyys1(x,ans));
47     return ans;
48 }
49 int main()
50 {lol x,y;
51 lol ans;
52     cin>>n>>m>>q;
53     sum=max(n,m)+q;
54     while (q--)
55     {
56         scanf("%lld%lld",&x,&y);
57         if (y==m) ans=zyys1(x,0);
58         else ans=zyys2(x,y);
59         printf("%lld\n",ans);
60     }
61 }

 

posted @ 2017-12-20 12:51  Z-Y-Y-S  阅读(358)  评论(0编辑  收藏  举报