[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.修改某一位值上的 ...
随机推荐
- 【BZOJ】4318: OSU! 期望DP
[题意]有一个长度为n的01序列,每一段极大的连续1的价值是L^3(长度L).现在给定n个实数表示该位为1的概率,求期望总价值.n<=10^5. [算法]期望DP [题解]后缀长度是一个很关键的 ...
- 20155335俞昆《Java程序设计》第五周总结
# 20155335 <Java程序设计>第五周学习总结 ## 教材学习内容总结 ## 教材学习中的问题和解决过程 对于异常处理,程序中总有意想不到的状况所引发的的错误,Jav ...
- 【洛谷 P3965】 [TJOI2013]循环格(费用流)
题目链接 回路限制经典题. 每个点拆成入点和出点,源点连每个点的出点,流量1,费用0,每个点出点连汇点,流量1,费用0,入点和出点之间没有边. 也就是说每个点必须靠其他点流来的流量来流入汇点,同时自己 ...
- 天梯赛 L1-006 连续因子 (模拟)
一个正整数N的因子中可能存在若干连续的数字.例如630可以分解为356*7,其中5.6.7就是3个连续的数字.给定任一正整数N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列. 输入格式 ...
- vue--------脚手架vue-cli搭建
今天在看公司的项目的时候,用到的是Vue框架,哈哈,Vue已经火好久了,想必大家也晓得哈,这里宝宝就不瞎渣渣了~ 由于宝宝已经三个月木有看过代码了,所以对新公司的很多的架构和代码都是懵逼的,再加上宝宝 ...
- 在wamp下增加多版本的PHP(PHP5.3,PHP5.4,PHP5.5)支持
1.安装WAMPServer 根据自己的操作系统选择相应的WAMP版本,我这里选择WAMPSERVER-32 BITS & PHP 5.5-2.5, 双击安装,选择安装目录即可,超级简单.根据 ...
- 33、求按从小到大的顺序的第N个丑数
一.题目 把只包含因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. 二.解法 ...
- SQLite3 C/C++ 开发接口简介(API函数)
from : http://www.sqlite.com.cn/MySqlite/5/251.Html 1.0 总览 SQLite3是SQLite一个全新的版本,它虽然是在SQLite 2.8.13的 ...
- usb_submit_urb 解释的够够的
/** * usb_submit_urb - issue an asynchronous transfer request for an endpoint * @urb: pointer to the ...
- (转)USB体系结构
转载地址:http://blog.ednchina.com/zenhuateng/203584/Message.aspx USB总线接口层:物理连接.电气信号环境.信息包传输机制:主机一方由USB主控 ...