[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.修改某一位值上的 ...
随机推荐
- 用Matlab实现字符串分割(split)
用Matlab实现字符串分割(split)Posted on 2011/08/08 Matlab的字符串处理没有C#强大,本身又没有提供OO特性,需要依赖别的手段完成这项任务. 我们在这里借助正则表达 ...
- PHPMailer发送邮件(一)
Github 地址:(已更新,适用于旧版) PHPMailer : https://github.com/PHPMailer/PHPMailer 一.基本要求 Web访问正常(apache可以正常访问 ...
- virtualenv搭建虚拟环境
最近因为项目需要,要在CentOS 7 上搭建一套开发环境,虽说Python的背后有着庞大的开源社区支持,但是有一个缺点就是每个包的质量都参差不齐,如果我们在工作服务器上去测试安装每个包,就会造成整个 ...
- Linux 下解决安装多个node冲突的问题(重新安装node)
一个系统中不经意安装了多个node版本,结果更新后还是原来的版本,下面思考一下解决办法: 敲黑板: 1. nodejs 用 包管理器安装一般在 /usr/local/bin 2. 查看当前目录下的no ...
- [LeetCode] Intersection of Two Linked Lists 两链表是否相交
Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...
- xv6/bootasm.S + xv6/bootmain.c
xv6/bootasm.S #include "asm.h" #include "memlayout.h" #include "mmu.h" ...
- 011 CountDownLatch,CyclicBarrier和Semaphore
CountDownLatch(闭锁,有译倒计数,锁寄存): public class CountDownLatchTest { /*** 比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此 ...
- Ural Sport Programming Championship 2015
Ural Sport Programming Championship 2015 A - The First Day at School 题目描述:给出课程安排,打印一个课程表. solution 暴 ...
- [ python ] 字符串的操作及作业题
字符串的操作方法 capitalize() : 首字母大写 s1 = 'my heart will go on' print(s1.capitalize()) # 首字母大写 # 执行结果: # My ...
- Valid Sudoku&&Sudoku Solver
Valid Sudoku Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku bo ...