[NOIP2017]列队 离线+SBT
[NOIP2017]列队
题目描述
Sylvia 是一个热爱学习的女♂孩子。
前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。
Sylvia 所在的方阵中有n×m名学生,方阵的行数为 n,列数为 m。
为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 n×m 编上了号码(参见后面的样例)。即:初始时,第 i 行第 j 列 的学生的编号是(i−1)×m+j。
然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 q件这样的离队事件。每一次离队事件可以用数对(x,y)(1≤x≤n,1≤y≤m)描述,表示第 x 行第 y 列的学生离队。
在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:
向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 x 行第 m 列。
- 向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 n 行第 m 列。
教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 n 行 第 m 列一个空位,这时这个学生会自然地填补到这个位置。
因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少。
注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。
输入输出格式
输入格式:
输入共 q+1 行。
第 1 行包含 3 个用空格分隔的正整数 n,m,q,表示方阵大小是 n 行 m 列,一共发 生了 q 次事件。
接下来 q 行按照事件发生顺序描述了 q 件事件。每一行是两个整数 x,y,用一个空 格分隔,表示这个离队事件中离队的学生当时排在第 x 行第 y 列。
输出格式:
按照事件输入的顺序,每一个事件输出一行一个整数,表示这个离队事件中离队学 生的编号。
输入输出样例
2 2 3
1 1
2 2
1 2
1
1
4
说明
【输入输出样例 1 说明】
列队的过程如上图所示,每一行描述了一个事件。 在第一个事件中,编号为 1 的同学离队,这时空位在第一行第一列。接着所有同学 向左标齐,这时编号为 2 的同学向左移动一步,空位移动到第一行第二列。然后所有同 学向上标齐,这时编号为 4 的同学向上一步,这时空位移动到第二行第二列。最后编号 为 1 的同学返回填补到空位中。
【数据规模与约定】
数据保证每一个事件满足 1≤x≤n,1≤y≤m
题解:由于操作是可逆的,所以我们将所有操作反过来做,将人的移动改成询问的反向移动,那么我们只需要维护这些询问点的移动即可,不难想到用数据结构(谁告诉我NOIP考前千万别做数据结构的~)
我们将操作顺序反过来,那么一次操作(x,y)可以看成:
1.(n,m)的学生出队
2.第n列中,第x行及以下的所有学生下移一格
3.第x行中,第y列及右面的所有学生右移一格
4.将当前询问的学生放到(x,y)处
鉴于这些操作,我最终选择了SBT(平衡树),那么1操作就是单点删除,2,3操作就是区间加法,4操作就是单点加入。我们对每一行,以及最后一列都开一棵SBT,维护其中的所有询问即可。
并且注意:每一行y的范围是[1,m),即如果一行的最右面的元素位于最后一列,我们要将其从这一行删除,并加入到最后一列中。
还有一点,如果在操作1时(n,m)处有询问,说明那个询问与当前询问是重合的,所以我们记录一个类似于pre的东西,将那个询问的pre指向当前询问,并将那个询问删除。输出答案的时候直接令该询问的答案等于其pre的答案即可。
正解是树状数组?不管了考场上想不到,写个大数据结构得了,倒是调了将近1个半点。
最后的最后。。。注意答案是爆int的!!!(没错我就是这么滚粗的~)
P.S:考完发现懵逼了,好像不离线也行。。。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=300010;
typedef long long ll;
struct node
{
int ch[2],siz,val,org,tag;
}s[maxn<<1];
int n,m,q,tot;
int rx,ry[maxn];
//px指最右面那列,py指每一行
int bel[maxn],x[maxn],y[maxn];
ll ans[maxn];
inline int rd()
{
int ret=0; char gc=getchar();
while(gc<'0'||gc>'9') gc=getchar();
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret;
}
inline void pushdown(int x)
{
if(s[x].tag)
{
if(s[x].ch[0]) s[s[x].ch[0]].val+=s[x].tag,s[s[x].ch[0]].tag+=s[x].tag;
if(s[x].ch[1]) s[s[x].ch[1]].val+=s[x].tag,s[s[x].ch[1]].tag+=s[x].tag;
s[x].tag=0;
}
}
inline void pushup(int x)
{
s[x].siz=s[s[x].ch[0]].siz+s[s[x].ch[1]].siz+1;
}
inline void rotate(int &x,int d)
{
int y=s[x].ch[d];
pushdown(x),pushdown(y);
s[x].ch[d]=s[y].ch[d^1],s[y].ch[d^1]=x;
pushup(x),pushup(y);
x=y;
}
inline void maintain(int &x,int d)
{
if(s[s[s[x].ch[d]].ch[d]].siz>s[s[x].ch[d^1]].siz) rotate(x,d);
else if(s[s[s[x].ch[d]].ch[d^1]].siz>s[s[x].ch[d^1]].siz) rotate(s[x].ch[d],d^1),rotate(x,d);
else return ;
maintain(s[x].ch[d],d),maintain(s[x].ch[d^1],d^1);
maintain(x,d),maintain(x,d^1);
}
void insert(int &x,int y,int z)
{
if(!x)
{
x=++tot,s[x].siz=1,s[x].ch[0]=s[x].ch[1]=s[x].tag=0,s[x].val=y,s[x].org=z;
return ;
}
pushdown(x);
int d=(y>s[x].val);
insert(s[x].ch[d],y,z),pushup(x);
maintain(x,d);
}
void del(int &x,int y)
{
s[x].siz--,pushdown(x);
if(s[y].val>s[x].val) del(s[x].ch[1],y);
else if(s[y].val<s[x].val) del(s[x].ch[0],y);
else
{
if(!s[x].ch[0]||!s[x].ch[1])
{
x=s[x].ch[0]^s[x].ch[1];
return ;
}
int u=s[x].ch[1]; pushdown(u);
while(s[u].ch[0]) u=s[u].ch[0],pushdown(u);
s[x].org=s[u].org,s[x].val=s[u].val;
del(s[x].ch[1],u);
}
}
void updata(int x,int y)
{
if(!x) return ;
pushdown(x);
if(s[x].val>=y)
{
s[x].val++;
if(s[x].ch[1]) s[s[x].ch[1]].val++,s[s[x].ch[1]].tag++;
updata(s[x].ch[0],y);
}
else updata(s[x].ch[1],y);
}
inline int findmax(int x)
{
pushdown(x);
while(s[x].ch[1]) x=s[x].ch[1],pushdown(x);
return x;
}
inline ll point(int a,int b) {return ll(a-1)*m+b;}
void dfs(int x,int t)
{
if(!x) return ;
pushdown(x);
if(!t) ans[s[x].org]=point(s[x].val,m);
else ans[s[x].org]=point(t,s[x].val);
dfs(s[x].ch[0],t),dfs(s[x].ch[1],t);
}
int find(int x,int y)
{
if(!x) return 0;
pushdown(x);
if(y>s[x].val) return find(s[x].ch[1],y);
if(y<s[x].val) return find(s[x].ch[0],y);
return x;
}
int main()
{
//freopen("phalanx.in","r",stdin);
//freopen("phalanx.out","w",stdout);
n=rd(),m=rd(),q=rd();
int i;
for(i=1;i<=q;i++)
{
bel[i]=i;
x[i]=rd(),y[i]=rd();
}
for(i=q;i>=1;i--)
{
int t=findmax(rx);
if(s[t].val==n)
{
bel[s[t].org]=i,del(rx,t);
}
updata(rx,x[i]);
updata(ry[x[i]],y[i]);
t=findmax(ry[x[i]]);
if(s[t].val==m)
{
del(ry[x[i]],t),insert(rx,x[i],s[t].org);
}
if(y[i]<m) insert(ry[x[i]],y[i],i);
else insert(rx,x[i],i);
}
dfs(rx,0);
for(i=1;i<=n;i++) dfs(ry[i],i);
for(i=1;i<=q;i++) printf("%lld\n",ans[i]=ans[bel[i]]);
return 0;
}
[NOIP2017]列队 离线+SBT的更多相关文章
- 题解[NOIP2017] 列队
题解[NOIP2017] 列队 题面 解析 看到这题时感觉这个编号很难维护啊? 后来看了lzf大佬的题解才会.. 首先,考虑一个稍微暴力的做法, 维护每一行的前\(m-1\)个人和最后一列的\(n\) ...
- NOIP2017列队(phalanx)解题报告
列队作为NOIP2017最后一道题,其实并不难,只是相对于其它题目,有点小小的工业 首先,这道题我用splay维护的,如果你不会splay,又想学一下splay,可以来这里学一学,接下来步入正题 首先 ...
- NOIP2017 列队 题解报告【56行线段树】
题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n \times mn×m名学生,方阵的行数 ...
- [NOIP2017]列队 (Splay)
题目链接 NOIP2017真的是不按常理出牌: 1.数学题不在Day2T1 2.一道水题一道细节极多的模拟题一道不知道怎么形容的题(小凯的疑惑)(因为我太菜了) 3.3道大火题 当时看到列队这题是毫无 ...
- NOIP2017 列队
https://www.luogu.org/problemnew/show/P3960 p<=500 50分 模拟 每个人的出队只会影响当前行和最后一列 p<=500,有用的行只有500行 ...
- <noip2017>列队
题解: 考场实际得分:45 重新看了一下,发现至少80分是很好拿的 对于前30% 暴力 另20% 显然离线搞一下就可以了(大概当初连离线是啥都不知道) 另另30%其实只要维护第一行和最后一列就可以了, ...
- [NOIP2017]列队(树状数组)
定义第i行为所有的点(i,j),0<j<m 可以发现,每一行是相对独立的,每一次操作只会影响到当前行和最后一列 考虑每一行和最后一列各开一个树状数组,但这样显然会爆空间 实际上,对于没有离 ...
- [UOJ#334][NOIP2017]列队 平衡树/线段树/树状数组
题目链接 题意不说了,一辈子也忘不掉 解法1.平衡树 这题就是平衡树裸题,每一行开一棵维护前 \(m-1\) 个,最后一列单独维护,因为很多人没有用到,所以平衡树每个节点是一个区间(pair),分裂时 ...
- [NOIP2017] 列队(平衡树)
考虑转化题意: 设这次操作删掉点\((x, y)\) 对于每一次向左看齐:在第x行删除\((x, y)\),并将y以后的点全部前移一位 对于每一次向前看齐:x以后的点全部上移一位,并在最后一列插入\( ...
随机推荐
- DevExpress实现GridControl删除所有行的方法
/// <summary> /// 删除全部行 /// </summary> /// <param name="gridView">GridVi ...
- informix遇到错误 25571:Cannot create an user thread
今天发现informix数据库不能用dbaccess访问,报错: 25571: Cannot create an user thread. On NT check username, and IX ...
- 安装vim 出现 terminal libary 错误,解决方法
通过源码安装vim时,提示缺少terminal libary 而在安装ncurses以后,此问题照样出现. 经过查找资料发现.运行例如以下命令就能够正常安装vim <pre name=" ...
- eclipse配置 嵌入式-基于linux
Eclipse可以安装在各种操作系统.这里是安装到Ubuntu 10.10上.有两种方法实现安装,一是采用Ubuntu的软件源:二是从官方下载后解压. 1. 通过Ubuntu软件源安装 $ sudo ...
- Django And Django-Rest-Framework 异常记录
1.TypeError: init() takes 1 positional argument but 2 were given
- cocosbuilder的一些坑
主要是大小写问题 在扁平发布模式下,如果存在大小写不同的文件,文件会被替换掉.而模拟上运行没问题,在真机上运行 有问题.找了半天才发现,坑啊!
- CentOS下yum安装PostgreSQL
关键词:centos install PostgreSQL Configure YUM repository vim /etc/yum.repos.d/CentOS-Base.repo [base] ...
- 解决异常:Package should contain a content type part [M1.13]
http://blog.csdn.net/llwan/article/details/8890190 ————————————————————————————————————————————————— ...
- SSIS 自测题-控制流控件类
说明:以下是自己的理解答案,不是标准的答案,如有不妥烦请指出. 有些题目暂时没有答案,有知道的请留言,互相学习,一起进步. 62.描述一下 Execute SQL Task 的作用,在 ...
- 在Javascript弹出窗口中输入换行符
private void showMessage(string strMsg) { Page.RegisterStartupScript("scriptStr", "&l ...