Luogu3960 NOIP2017列队(splay/线段树)
令splay中的一个点表示一段区间,需要使用其中某个点时将区间分裂即可,剩下的都是splay的基本操作了。写的非常丑陋,注意细节。感觉考场上肯定只能靠部分分苟活了。想起来去年因为各种莫名其妙的原因50->0
考虑一维时的线段树做法。维护区间内有多少人,每次找到第x个人把他拿出来放到最后就行了。扩展到二维动态开点即可。不写了
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 300010
#define lson tree[k].ch[0]
#define rson tree[k].ch[1]
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,m,q,row[N],line,cnt;
struct data{int ch[],fa,len,size;ll id;
}tree[N<<];
ll trans(int x,int y){return 1ll*(x-)*m+y;}
void up(int k){tree[k].size=tree[lson].size+tree[rson].size+tree[k].len;}
int whichson(int k){return tree[tree[k].fa].ch[]==k;}
void move(int k)
{
int fa=tree[k].fa,gf=tree[fa].fa,p=whichson(k);
tree[gf].ch[whichson(fa)]=k,tree[k].fa=gf;
tree[tree[k].ch[!p]].fa=fa,tree[fa].ch[p]=tree[k].ch[!p];
tree[k].ch[!p]=fa,tree[fa].fa=k;
up(fa),up(k);
}
void splay(int k,int rt,int &root)
{
while (tree[k].fa!=rt)
{
int fa=tree[k].fa;
if (tree[fa].fa!=rt)
if (whichson(fa)^whichson(k)) move(k);
else move(fa);
move(k);
}
if (!rt) root=k;
}
int find(int k,int x)
{
if (tree[lson].size<x&&tree[lson].size+tree[k].len>=x) return k;
else if (tree[lson].size>=x) return find(lson,x);
else return find(rson,x-tree[lson].size-tree[k].len);
}
int getid(int k,int x)
{
if (tree[lson].size<x&&tree[lson].size+tree[k].len>=x) return x-tree[lson].size;
else if (tree[lson].size>=x) return getid(lson,x);
else return getid(rson,x-tree[lson].size-tree[k].len);
}
int nxt(int k){if (!lson) return k;return nxt(lson);}
void ins(int &k,int l,int r,ll id)
{
cnt++;tree[cnt].size=tree[cnt].len=r-l+,tree[cnt].id=id;
int p=find(k,l);splay(p,,k);
int q=nxt(tree[p].ch[]);splay(q,p,k);
tree[q].ch[]=cnt;tree[cnt].fa=q;up(q);up(p);
}
void del(int &k,int l,int r)
{
int p=find(k,l),q=find(k,r+);
splay(p,,k);splay(q,p,k);
tree[q].ch[]=;up(q);up(p);
}
ll split(int x,int y)
{
int k=find(row[x],y+),p=getid(row[x],y+);
del(row[x],y-p+,y+tree[k].len-p);
if (p>) ins(row[x],y-p+,y-,tree[k].id);
if (p<tree[k].len) ins(row[x],y,y+tree[k].len-p-,tree[k].id+p);
return tree[k].id+p-;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("phalanx.in","r",stdin);
freopen("phalanx.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read(),q=read();
for (int i=;i<=n;i++)
{
row[i]=++cnt;tree[cnt].len=m-,tree[cnt].size=m+;tree[cnt].id=trans(i,);
cnt++;tree[cnt].len=tree[cnt].size=;tree[cnt].fa=row[i],tree[row[i]].ch[]=cnt;
cnt++;tree[cnt].len=tree[cnt].size=;tree[cnt].fa=row[i],tree[row[i]].ch[]=cnt;
}
line=++cnt;tree[cnt].len=,tree[cnt].size=;
cnt++;tree[cnt].len=tree[cnt].size=;tree[cnt].fa=line,tree[line].ch[]=cnt;
for (int i=;i<=n;i++) ins(line,i,i,trans(i,m));
while (q--)
{
int x=read(),y=read();
ll id;
if (y<m)
{
id=split(x,y);
int k=find(line,x+);
del(line,x,x);
ins(row[x],m-,m-,tree[k].id);
}
else
{
int k=find(line,x+);
del(line,x,x);
id=tree[k].id;
}
ins(line,n,n,id);
printf(LL,id);
}
return ;
}
Luogu3960 NOIP2017列队(splay/线段树)的更多相关文章
- Luogu 3960 [NOIP2017] 列队 - splay|线段树
题解 是我从来没有做过的裂点splay... 看的时候还是很懵逼的QAQ. 把最后一列的$n$个数放在一个平衡树中, 有 $n$ 个点 剩下的$n$行数, 每行都开一个平衡树,开始时每棵树中仅有$1$ ...
- noip2017列队(线段树)
维护一个方阵,支持 1.删掉一个点,剩下的点先向左看齐再向前看齐 2.询问一个位置上是哪个点 $n,m,q \leq 3 \times 10^5$ sol: 我们每行前$m-1$列维护一个线段树,最后 ...
- [UOJ#334][NOIP2017]列队 平衡树/线段树/树状数组
题目链接 题意不说了,一辈子也忘不掉 解法1.平衡树 这题就是平衡树裸题,每一行开一棵维护前 \(m-1\) 个,最后一列单独维护,因为很多人没有用到,所以平衡树每个节点是一个区间(pair),分裂时 ...
- NOIp2017 列队(线段树)
嘛..两年前的题目了,想起第一次参加提高组还骗了一个省二回来呢...跟同学吹了好久的... 离退役又近了一骗博客啊.. 闲聊结束. 照常化简:给定一个1-n*m编号的矩阵,每次删除一个位置,然后左边向 ...
- 2018.11.01 loj#2319. 「NOIP2017」列队(线段树)
传送门 唉突然回忆起去年去noipnoipnoip提高组试水然后省二滚粗的悲惨经历... 往事不堪回首. 所以说考场上真的有debuffdebuffdebuff啊!!!虽然当时我也不会权值线段树 这道 ...
- LOJ2319. 「NOIP2017」列队【线段树】
LINK 思路 神仙线段树 你考虑怎么样才能快速维护出答案 首先看看一条链怎么做? 首先很显然的思路是维护每个节点的是否出过队 然后对于重新入队的点 直接在后面暴力vector存一下就可以了 最核心的 ...
- BZOJ4561:圆的异或并(扫描线+set||splay||线段树)
在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面 积并.异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆内则不考虑. I ...
- CodeForces 85D Sum of Medians Splay | 线段树
Sum of Medians 题解: 对于这个题目,先想到是建立5棵Splay,然后每次更新把后面一段区间的树切下来,然后再转圈圈把切下来的树和别的树合并. 但是感觉写起来太麻烦就放弃了. 建立5棵线 ...
- Splay(区间翻转)&树套树(Splay+线段树,90分)
study from: https://tiger0132.blog.luogu.org/slay-notes P3369 [模板]普通平衡树 #include <cstdio> #inc ...
随机推荐
- mac phpstorm 破解方法
方法参考如下链接: 来源:http://www.cnblogs.com/zyliang/p/6148960.html
- VSCode插件整理
VSCode插件整理 VSCode插件整理 官网地址 vscode常用配置(User Settings文件) 基本插件 前端插件 VUE部分 python MarkDown部分 连接Linux 本地与 ...
- Python系列5之模块
模块 1. 模块的分类 模块,又称构件,是能够单独命名并独立地完成一定功能的程序语句的集合(即程序代码和数据结构的集合体). (1)自定义模块 自己定义的一些可以独立完成某个功能的一段程序语句,可以是 ...
- python-time模块、sys模块、os模块以及大量实例
模块 通俗的说模块就把一个已经写好的带有可使用的函数的文件,通过文件名进行导入,然后调用里面的函数等来完成所需功能,模块封装了你需要实现功能的代码,使用者只需调用即可,简化代码量,缩短编程时间. ti ...
- uva 509 RAID!(磁盘数据)
来自 https://blog.csdn.net/su_cicada/article/details/80085318 习题4-7 RAID技术(RAID!, ACM/ICPC World Final ...
- [BZOJ1455]罗马游戏(左偏树)
用并查集和左偏树维护士兵的关系 Code #include <cstdio> #include <algorithm> #define N 1000010 using name ...
- WPF中的ControlTemplate(控件模板)
原文:WPF中的ControlTemplate(控件模板) WPF中的ControlTemplate(控件模板) ...
- 1826: [JSOI2010]缓存交换
1826: [JSOI2010]缓存交换 https://www.lydsy.com/JudgeOnline/problem.php?id=1826 分析: 简单的贪心,然后调啊调...最近怎么了,码 ...
- (原)一段看似美丽的for循环,背后又隐藏着什么
之前很长一段时间,潜心修炼汇编,专门装了一个dos7,慢慢玩到win32汇编,再到linux的AT&A汇编,尝试写mbr的时候期间好几次把centos弄的开不了机,又莫名其妙的修好了,如今最大 ...
- (3)分布式下的爬虫Scrapy应该如何做-递归爬取方式,数据输出方式以及数据库链接
放假这段时间好好的思考了一下关于Scrapy的一些常用操作,主要解决了三个问题: 1.如何连续爬取 2.数据输出方式 3.数据库链接 一,如何连续爬取: 思考:要达到连续爬取,逻辑上无非从以下的方向着 ...