嘛。。两年前的题目了,想起第一次参加提高组还骗了一个省二回来呢。。。跟同学吹了好久的。。。

离退役又近了一骗博客啊。。

闲聊结束。

照常化简:给定一个1-n*m编号的矩阵,每次删除一个位置,然后左边向右补,之后后面向前补,最后空出来的位置再由刚刚删去的点补上,求每次删除的点的编号。

当年也是暴力,奔着30pts就去了,结果奈何手欠数组开大了全部MLE。。。

但是正解也就从这里延伸。

首先,直接地,删除,增加,维护序列,能想到的东西差不多就是平衡树了。。。

但是,考场上大打Splay绝对不可能(日常也不可能打,我是连线段树都能写错的蒟蒻)

所以果断放弃。。

通过观察,晓得每次删除/填补只会有当前行和最后一列,还有最后一行的一个点变化。

于是,经过一年的思考和集训老师的解说,我明白了,可以用线段树写。

把用过的扔到后面,然后通过线段树的操作获得答案(下面再讲)

开n+1个线段树,维护每一行和最后一列。

为了防止数组出锅,我们要尽可能开大,所以要开(max(n,m)+q)*(n+1)个,然鹅这个数组应该达到了TB级别。。。

最终数据有900亿人(超级教官&&银河军训),而询问数量却很小,也就是说,有很多空间都没有用过,所以使用动态开点线段树,需要用的时候再找内存要空间。

然后来考虑怎么查询&&维护。

首先,线段树没有平衡树这么多神仙操作,所以要用公式或者记录某些东西来获得编号

  1. 如果没有动过,一切好说,直接乘法加法计算即可
  2. 如果是最后一列直接搞

问题就在于怎么查中间的。

记录一下每一行缺了多少人,(1-n之内跑了多少,下统称size),然后每次只需要比较查询的那个大小和size的大小就可以获得“方向”了。

  1. 如果size大,说明要求的东西不在原序列里,要另查
  2. 如果size小,说明我们可以继续在当前区间乱搞了

怎么乱搞呢?记录一下每一行缺的是哪个点,如果初始没有动的话直接公式搞定如果中间动过的话,就一系列骚操作通过记录的东西获得答案。

然后每次用答案去更新序列

然后就是代码了,有注释

#include<bits/stdc++.h>
#define ll long long
#define ill inline long long
using namespace std;
inline int read()
{
int x=,f=;char s=getchar();
while(s>''||s<''){if(s=='-')f=-;s=getchar();}
while(s<=''&&s>=''){x=x*+s-'';s=getchar();}
return x*f;
}
const ll maxn=6e6+;
int n,m,q;
int size[maxn];//第i行1-n中有多少缺失的(即动态开多少点)
ll tre[maxn];//每一行却的点的编号 (动态变化,每次只缺一个)
int ls[maxn];
int rs[maxn];
int R[maxn];//行/最后一列的长度(开完之后)
int cnt;
ill find_row(int l,int r,int x,int y,int &k)
{
if(!k)
k=++cnt;
size[k]++;
if(l==r)
{
if(tre[k]==)return (ll)(x-)*m+r;
else return tre[k];
}
int mid=l+r>>;
if(mid-l+-size[ls[k]]>=y)return find_row(l,mid,x,y,ls[k]);
else{ y-=mid-l+-size[ls[k]];return find_row(mid+,r,x,y,rs[k]);}
}
ill findline(int l,int r,int x,int y,int &k)
{
if(!k)
k=++cnt;
size[k]++;
if(l==r)
{
if(tre[k]==)return (ll)(l-)*m+y;
else return tre[k];
}
int mid=l+r>>;
if(mid-l+-size[ls[k]]>=x)return findline(l,mid,x,y,ls[k]);
else {x-=mid-l+-size[ls[k]];return findline(mid+,r,x,y,rs[k]);}
}
void add(int l,int r,ll v,int x,int &k)
{
if(!k)
k=++cnt;
if(l==r)
{
tre[k]=v;
return;
}
int mid=l+r>>;
if(x<=mid)add(l,mid,v,x,ls[k]);
else add(mid+,r,v,x,rs[k]);
}
int main()
{
//scanf("%d%d%d",&n,&m,&q);
n=read();
m=read();
q=read();
int r=max(n,m)+q;
cnt=n+;
while(q--)
{
int x,y;
x=read();
y=read();//scanf("%d%d",&x,&y);
if(y==m)
{
int k=n+;
ll ans=findline(,r,x,y,k);
printf("%lld\n",ans);
R[n+]++;add(,r,ans,R[n+]+n,k);
}
else
{
int k=n+;
ll ans=find_row(,r,x,y,x);
ll tem=findline(,r,x,m,k);
printf("%lld\n",ans);
R[x]++;add(,r,tem,R[x]+m-,x);
R[n+]++;add(,r,ans,R[n+]+n,k);
}
}
return ;
}

NOIp2017 列队(线段树)的更多相关文章

  1. [NOIP2017]列队(线段树/裂点splay)

    考虑n=1的做法,就是支持: 1.在线删一个数 2.在结尾加一个数 3.查询序列的第y个数 用线段树记录区间内被删元素的个数,可以通过线段树上二分快速得解,对于新增的数,用vector记录即可. 对于 ...

  2. [NOIP2017]列队 线段树

    ---题面--- 题解: 之前写的splay,,,然而一直没调出来,我感觉是某个细节想错了,,然而已经重构4次代码不想再写splay了.于是今天尝试了线段树的解法. 首先因为每次出列之后的变化都是将当 ...

  3. 【noip2017】【Luogu3960】列队 线段树

    题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 n \times mn×m 名学生,方阵的 ...

  4. Luogu P3960 列队 线段树

    题面 线段树入门题. 我们考虑线段树来维护这个矩阵. 首先我们先定n+1棵线段树前n棵维护每行前m-1个同学中没有离队过的同学,还有一棵维护第m列中没有离队过的同学.再定n+1棵线段树前n棵线段树维护 ...

  5. 洛谷 P3960 [ NOIP 2017 ] 列队 —— 线段树

    题目:https://www.luogu.org/problemnew/show/P3960 NOIP 题,不用很复杂的数据结构...但又参考了许多: 要求支持维护删除第 k 个和在末尾插入的数据结构 ...

  6. [NOIP2017]列队(树状数组)

    定义第i行为所有的点(i,j),0<j<m 可以发现,每一行是相对独立的,每一次操作只会影响到当前行和最后一列 考虑每一行和最后一列各开一个树状数组,但这样显然会爆空间 实际上,对于没有离 ...

  7. NOIP2017 列队 题解报告【56行线段树】

    题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n \times mn×m名学生,方阵的行数 ...

  8. NOIP2017提高组Day2T3 列队 洛谷P3960 线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/9265380.html 题目传送门 - 洛谷P3960 题目传送门 - LOJ#2319 题目传送门 - Vij ...

  9. 洛谷P3960 列队 NOIp2017 线段树/树状数组/splay

    正解:动态开点线段树 解题报告: 传送门! 因为最近学主席树的时候顺便get到了动态开点线段树?刚好想起来很久很久以前就想做结果一直麻油做的这题,,,所以就做下好了QAQ 然后说下,这题有很多种方法, ...

  10. 2018.11.01 loj#2319. 「NOIP2017」列队(线段树)

    传送门 唉突然回忆起去年去noipnoipnoip提高组试水然后省二滚粗的悲惨经历... 往事不堪回首. 所以说考场上真的有debuffdebuffdebuff啊!!!虽然当时我也不会权值线段树 这道 ...

随机推荐

  1. Zygote家的大儿子 —— SystemServer

    本文基于 Android 9.0 , 代码仓库地址 : android_9.0.0_r45 文中源码链接: SystemServer.java SystemServiceManager.java Sy ...

  2. centos 7安装rac 11gR2时运行root.sh报错找不到ohas服务(ohasd failed to start)

    单独在linux 7中为ohasd设置一个服务.步骤如下1. 创建服务ohas.service的服务文件并赋予权限touch /usr/lib/systemd/system/ohas.servicec ...

  3. 单引号、双引号与定界符——PHP

    单引号与双引号 单引号和双引号在echo输出时的区别 echo输出时,如果使用单引号,那么echo会把单引号之间的全部内容当成普通字符串输出,不能识别变量和转义字符(单引号串中的内容总被认为是普通字符 ...

  4. Ubuntu php + apache

    Ubuntu 环境: 问题1: apache 不能解析 *.php 文件 安装apache的扩展模块 :  apt-get install libapache2-mod-php 问题2 : 客户端访问 ...

  5. vue+element 实现商品sku效果

    在网上搜索了很久,没有发现合适sku编辑的文章,只能自己写一个vue+element 的sku编辑功能.实现的效果如下图 除成本.售价.库存.货号这几个写死的属性外,可自行添加/删除商品属性,自行添加 ...

  6. [牛客网NOIP赛前集训营-普及组(第二场)]D-合法括号序列

    链接:https://www.nowcoder.com/acm/contest/165/D来源:牛客网 合法括号序列 键盘上有左括号(,右括号),和退格键-,共三个键. 牛牛希望按键n次,使得输入的字 ...

  7. webpack——npm -i 与npm install -s与-d的区别

    在 package.json 文件里面的[devDependencies]和[dependencies]对象有什么区别呢? devDependencies  里面的插件只用于开发环境,不用于生产环境, ...

  8. 开源造轮子:一个简洁,高效,轻量级,酷炫的不要不要的canvas粒子运动插件库

    一:开篇 哈哈哈,感谢标题党的莅临~ 虽然标题有点夸张的感觉,但实际上,插件库确实是简洁,高效,轻量级,酷炫酷炫的咯.废话不多说,先来看个标配例子吧: (codepen在线演示编辑:http://co ...

  9. 后缀数组(SA)

    学习了LRJ神犇的代码.orz. 首先真心建议了解下基数排序!!且要有一定的c++程序经验,否则程序很难看懂. 然后对着下面的程序调试(假装你已经会了算法思想) 弄个一个礼拜一下午就能学会了. 该算法 ...

  10. C加加学习之路 2——两招让你成为牛X的T型人才

    有个小伙伴在微信上问我: 我刚工作半年,有时候对于Java的发展方向有点迷茫,Java的范围是在是太广了,我有时候会不知道从哪开始入手,我想问一下,您有什么好的建议吗? 我理解这位朋友的问题是:工作中 ...