[NOIP2017]列队(线段树/裂点splay)
考虑n=1的做法,就是支持:
1.在线删一个数
2.在结尾加一个数
3.查询序列的第y个数
用线段树记录区间内被删元素的个数,可以通过线段树上二分快速得解,对于新增的数,用vector记录即可。
对于满分同样如此,对每行开一个线段树,再对最后一列单独开一个。
对于每次操作:
若在最后一列:就是对最后一列直接使用n=1的做法。
若不在:对第x列的前m-1个用n=1的做法,再将最后一列的第x个加入第x列的末尾,然后再对最后一列使用n=1的做法。
#include<cstdio>
#include<vector>
#include<algorithm>
#define lson ls[x],L,mid
#define rson rs[x],mid+1,R
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=,M=N*;
ll ans;
int n,m,Q,mx,x,y,nd,rt[N],sm[M],ls[M],rs[M];
vector<ll>V[N]; void ins(int &x,int L,int R,int pos){
if (!x) x=++nd;
if (L==R){ sm[x]++; return; }
int mid=(L+R)>>;
if (pos<=mid) ins(lson,pos); else ins(rson,pos);
sm[x]=sm[ls[x]]+sm[rs[x]];
} int que(int x,int L,int R,int pos){
if (L==R) return L;
int mid=(L+R)>>,t=mid-L+-sm[ls[x]];
if (t>=pos) return que(lson,pos); else return que(rson,pos-t);
} int main(){
scanf("%d%d%d",&n,&m,&Q); mx=max(n,m)+Q;
rep(i,,n) V[i].push_back();
while (Q--){
scanf("%d %d",&x,&y);
if (y==m){
int s=que(rt[],,mx,x);
if (s<=n) ans=1ll*s*m; else ans=V[][s-n];
printf("%lld\n",ans); ins(rt[],,mx,s); V[].push_back(ans);
continue;
}
int t=que(rt[x],,mx,y);
if (t<m) ans=1ll*(x-)*m+t; else ans=V[x][t-(m-)];
printf("%lld\n",ans); ins(rt[x],,mx,t);
int s=que(rt[],,mx,x); ll tmp=ans;
if (s<=n) ans=1ll*s*m; else ans=V[][s-n];
V[x].push_back(ans); ins(rt[],,mx,s); V[].push_back(tmp);
}
return ;
}
或裂点splay,一个点代表一个区间,每次删除某个位置k就将其裂为[l,k-1],k,[k+1,r]三个部分,再删掉k。
模板题。常数较大。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
int n,m,Q,nd,x,y,ch[N][],rt[N],f[N];
ll L[N],R[N],len[N]; int get(ll l,ll r){ nd++; L[nd]=l; R[nd]=r; len[nd]=r-l+; return nd; }
void upd(int x){ len[x]=len[ch[x][]]+len[ch[x][]]+R[x]-L[x]+; } void rot(int &rt,int x){
int y=f[x],z=f[y],w=ch[y][]==x;
if (y==rt) rt=x; else ch[z][ch[z][]==y]=x;
f[x]=z; f[y]=x; f[ch[x][w^]]=y;
ch[y][w]=ch[x][w^]; ch[x][w^]=y; upd(y);
} void splay(int &rt,int x){
while (x!=rt){
int y=f[x],z=f[y];
if (y!=rt) ((ch[z][]==y) ^ (ch[y][]==x)) ? rot(rt,x) : rot(rt,y);
rot(rt,x);
}
upd(x);
} void ins(int &rt,ll k){
int y=get(k,k);
if (!rt) { rt=y; return; }
int x=rt; while (ch[x][]) x=ch[x][];
splay(rt,x); f[y]=x; ch[x][]=y; upd(x);
} int split(int &rt,int x,ll k){
k+=L[x];
int y=get(k,R[x]); R[x]=k-;
if (!ch[x][]) f[y]=x,ch[x][]=y;
else{
int s=ch[x][];
while (ch[s][]) s=ch[s][];
f[y]=s; ch[s][]=y;
}
splay(rt,y); return y;
} int find(int x,ll &k){
if (k<=len[ch[x][]]) return find(ch[x][],k);
k-=len[ch[x][]];
if (k<=R[x]-L[x]+) return x; else return k-=R[x]-L[x]+,find(ch[x][],k);
} ll del(int &rt,ll k){
int x=find(rt,k);
if (k<R[x]-L[x]+) split(rt,x,k);
if (k>) x=split(rt,x,k-);
splay(rt,x); f[ch[x][]]=f[ch[x][]]=;
if (!ch[x][]) rt=ch[x][];
else{
int y=ch[x][]; rt=y;
while (ch[y][]) y=ch[y][];
splay(rt,y); ch[y][]=ch[x][];
f[ch[x][]]=y; upd(y);
}
return L[x];
} int main(){
freopen("phalanx.in","r",stdin);
freopen("phalanx.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q);
rep(i,,n) rt[i]=++nd,L[i]=(i-1ll)*m+,R[i]=1ll*i*m-,len[i]=R[i]-L[i]+;
rep(i,,n) ins(rt[],1ll*i*m);
while (Q--){
scanf("%d%d",&x,&y); ll ans;
ins(rt[x],del(rt[],x));
printf("%lld\n",ans=del(rt[x],y));
ins(rt[],ans);
}
return ;
}
[NOIP2017]列队(线段树/裂点splay)的更多相关文章
- [NOIP2017]列队 线段树
---题面--- 题解: 之前写的splay,,,然而一直没调出来,我感觉是某个细节想错了,,然而已经重构4次代码不想再写splay了.于是今天尝试了线段树的解法. 首先因为每次出列之后的变化都是将当 ...
- 【BZOJ 3196】二逼平衡树 线段树套splay 模板题
我写的是线段树套splay,网上很多人写的都是套treap,然而本蒟蒻并不会treap 奉上sth神犇的模板: //bzoj3196 二逼平衡树,支持修改某个点的值,查询区间第k小值,查询区间某个值排 ...
- BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay
传送门 题意 给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种: 查询 $ k $ 在区间 $ [l,r] $ 内的排名 查询区间 $ [l,r] $ 内排 ...
- 刷题总结——二逼平衡树(bzoj3224线段树套splay)
题目: Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在 ...
- 【noip2017】【Luogu3960】列队 线段树
题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 n \times mn×m 名学生,方阵的 ...
- ZOJ-2112-Dynamic Rankings(线段树套splay树)
题意: 完成两个操作: 1.询问一个区间里第k小的数: 2.修改数列中一个数的值. 分析: 线段树套平衡树,线段树中的每个节点都有一棵平衡树,维护线段树所记录的这个区间的元素.这样处理空间上是O(nl ...
- 【Luogu】P3380树套树模板(线段树套Splay)
题目链接 幸甚至哉,歌以咏志. 拿下了曾经是那么遥不可及的线段树,学会了曾经高不可攀的平衡树,弄懂了装B的时候才挂在嘴边的树套树. 每道模板都是链上的一颗珠子.把它们挨个串起来,就成为我成长的历程. ...
- bzoj 3196 Tyvj 1730 二逼平衡树【线段树 套 splay】
四舍五入就是个暴力. 对于线段树的每个区间都开一棵按权值排序的splay 对于第二个操作,二分一下,每次查询mid的排名,复杂度 $ O(nlog(n)^{3}) $ 其余的操作都是$ O(nlog( ...
- [BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)
传送门 至少BZOJ过了,其他的直接弃. 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的 ...
随机推荐
- 2017ACM暑期多校联合训练 - Team 5 1001 HDU 6085 Rikka with Candies (模拟)
题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...
- NYOJ 328 完全覆盖 (找规律)
题目链接 描述 有一天小董子在玩一种游戏----用21或12的骨牌把mn的棋盘完全覆盖.但他感觉游戏过于简单,于是就随机生成了两个方块的位置(可能相同),标记一下,标记后的方块不用覆盖.还要注意小董子 ...
- # 2018高考&自主招生 - 游记
准备了一整个学期的高考和自主招生终于结束了....从育英出来, 以一个失败者的身份来写游记, 权当为明年的决战提供经验与总结. Day -1, June 5th 下午同学收拾考场, 自己在那里看书.. ...
- 蓝色简单的cms文档管理系统模板——后台
链接:http://pan.baidu.com/s/1qYMwHis 密码:xyiw
- python设计模式之迭代器与生成器详解(五)
前言 迭代器是设计模式中的一种行为模式,它提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示.python提倡使用生成器,生成器也是迭代器的一种. 系列文章 python设计模 ...
- Petrozavodsk Winter Training Camp 2018
Petrozavodsk Winter Training Camp 2018 Problem A. Mines 题目描述:有\(n\)个炸弹放在\(x\)轴上,第\(i\)个位置为\(p_i\),爆炸 ...
- geoserver-manager发布style失败
当参数给定没有错误时,最有可能的原因就是: sld文件格式应该以UTF-8无BOM格式编码(自己生成的sld文件多数情况下是以UTF-8格式编码).
- 最全Pycharm教程(26)——Pycharm搜索导航之文件名、符号名搜索(转)
1.准备一个工程 向你的工程中添加一个Python文件,并输入一些源码,例如: 2.转到对应文件.类.符号 Pycharm提供的一个很强力的功能就是能够根据名称跳转到任何文件.类.符号所在定义位置. ...
- 详述Linux配置静态IP、设置DNS和主机名(一)
Linux配置静态IP.设置DNS和主机名首先要找到配置文件,这是在Linux系统下进行工作的必须知道工作方式.后面一步步的跟着这个范例来进行配置相信你最终也会完成Linux配置静态IP.设置DNS和 ...
- Python股票信息抓取(二)
在一的基础上,想着把所有的折线图放在一个图中,然后图的结果如图所示: 不是略丑,是很丑~ 依然的单进程,只是将图标结果放在了一张图里 代码如下: #-*-coding:utf-8 -*- import ...