[UOJ#334][NOIP2017]列队 平衡树/线段树/树状数组
题意不说了,一辈子也忘不掉
解法1.平衡树
这题就是平衡树裸题,每一行开一棵维护前 \(m-1\) 个,最后一列单独维护,因为很多人没有用到,所以平衡树每个节点是一个区间(pair),分裂时顺便把区间裂开来。这也是最暴力的解法
这里以Fhq_Treap为例(其实是我不熟练Splay)

//Fhq_Treap
//http://uoj.ac/submission/296955
#include<stdio.h>
#include<cctype>
#include<cstring>
#include<algorithm>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
const int S=1<<18;
char ibuf[S],obuf[S+128],*iS,*iT,*oS=obuf,*oT=obuf+S;
#define gc (iS==iT?iT=ibuf+fread(iS=ibuf,1,S,stdin),iS==iT?EOF:*iS++:*iS++)
inline int read(){char c;
while(isspace(c=gc));int w=c&15;
while(isdigit(c=gc))w=w*10+(c&15);return w;
}
inline void flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
#define printf(...) oS>oT&&(flush(),1),oS+=sprintf(oS,__VA_ARGS__)
typedef long long ll;
typedef std::pair<ll,ll>pll;
#define xx first
#define yy second
const int N=3e5+5;
int n,m,cnt,rt[N];
struct node{
int ls,rs,r,siz;
pll w;
}t[N<<3];
#define sz(o) (t[o].w.yy-t[o].w.xx+1)
inline void pushup(int o){t[o].siz=t[t[o].ls].siz+t[t[o].rs].siz+sz(o);}
inline int add(const ll&x,const ll&y){
int o=++cnt;t[o].w=pll(x,y);t[o].siz=y-x+1;
t[o].r=rand();t[o].ls=t[o].rs=0;
return o;
}
inline int merge(int x,int y){
if(!x||!y)return x|y;
if(t[x].r<t[y].r)
return t[x].rs=merge(t[x].rs,y),pushup(x),x;
return t[y].ls=merge(x,t[y].ls),pushup(y),y;
}
void split(int o,int k,int&x,int&y){
if(!k)x=0,y=o;else if(k==t[o].siz)x=o,y=0;
else{
if(k>=t[t[o].ls].siz+sz(o))
split(t[o].rs,k-t[t[o].ls].siz-sz(o),t[o].rs,y),x=o;
else{
if(k<=t[t[o].ls].siz)
split(t[o].ls,k,x,t[o].ls),y=o;
else{
k-=t[t[o].ls].siz;
int p=add(t[o].w.xx+k,t[o].w.yy);
t[o].w.yy=t[p].w.xx-1;
x=o,y=merge(p,t[o].rs);t[o].rs=0;
}
}
pushup(o);
}
}
int main(){
srand((unsigned long long)"THX_AK_NOIP2018");
n=read(),m=read();int q=read();
t[0].w=pll(1,0);
REP(i,1,n)rt[i]=add(1ll*m*(i-1)+1,1ll*i*m-1);
rt[0]=add(m,m);
REP(i,2,n){ll t=1ll*i*m;rt[0]=merge(rt[0],add(t,t));}
while(q--){
int x=read(),y=read(),a,b,c,d,p;
if(y!=m){
split(rt[x],y-1,a,b);
split(b,1,c,d);
rt[x]=merge(a,d);
p=c;
}
split(rt[0],x-1,a,b);
split(b,1,c,d);
if(y!=m)rt[x]=merge(rt[x],c);
rt[0]=merge(a,d);
if(y==m)p=c;
printf("%lld\n",t[p].w.xx);
rt[0]=merge(rt[0],p);
}
return flush(),0;
}
解法2.线段树
同样是每一行和最后一列维护线段树,但是把每次操作看做是新加的节点,最多有 \(Q\) 个
所以线段树值域是 \(max(n,m)+Q\) ,每个节点记录一下被删除节点的总数,然后查第k大时在线段树上二分,找到对应的节点。如果小于 \(n\) 或 \(m\) 就直接算,否则读取存下的 \(id\)

//Segment_Tree
//http://uoj.ac/submission/296972
#include<stdio.h>
#include<cctype>
#include<cstring>
#include<algorithm>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
const int S=1<<18;
char ibuf[S],obuf[S+128],*iS,*iT,*oS=obuf,*oT=obuf+S;
#define gc (iS==iT?iT=ibuf+fread(iS=ibuf,1,S,stdin),iS==iT?EOF:*iS++:*iS++)
inline int read(){char c;
while(isspace(c=gc));int w=c&15;
while(isdigit(c=gc))w=w*10+(c&15);return w;
}
inline void flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
#define printf(...) oS>oT&&(flush(),1),oS+=sprintf(oS,__VA_ARGS__)
typedef long long ll;
const int N=3e5+5;
struct node{int ls,rs,w;ll id;}t[N*70];
int n,m,q,cnt,c[N],rt[N];
inline void ins(int&o,int l,int r,int x,const ll&y){
if(!o)o=++cnt;
if(l==r){t[o].id=y;return;}
int mid=l+r>>1;
x<=mid?ins(t[o].ls,l,mid,x,y):ins(t[o].rs,mid+1,r,x,y);
}
inline ll del(int&o,int l,int r,int k,int x){
if(!o)o=++cnt;++t[o].w;
if(l==r){
if(!x&&l<=n)return 1ll*l*m;
if(x&&x<=n&&l<m)return 1ll*(x-1)*m+l;
return t[o].id;
}
int mid=l+r>>1,val=mid-l+1-t[t[o].ls].w;
return k<=val?del(t[o].ls,l,mid,k,x):del(t[o].rs,mid+1,r,k-val,x);
}
int main(){
n=read(),m=read(),q=read();int len=std::max(n,m)+q;
#define all 1,len
REP(i,1,n)c[i]=m-1;c[0]=n;
while(q--){
int x=read(),y=read();
ll p,q=del(rt[0],all,x,0);
if(y<m){
p=del(rt[x],all,y,x);
ins(rt[x],all,++c[x],q);
ins(rt[0],all,++c[0],p);
}else ins(rt[0],all,++c[0],q);
printf("%lld\n",y<m?p:q);
}
return flush(),0;
}
解法3.树状数组
考虑把刚刚的线段树用树状数组代替,查第 \(k\) 大可以倍增实现一个log
由于树状数组没办法动态开点,考虑离线下来
刚开始处理时,先把最后一列处理掉,
由于每次操作只会影响当前行和最后一列,因此可以逐行处理,对于每一个操作,倍增查第 \(k\) 大,然后把它删掉,如果这个数小于 \(m\) 则还在原队列里,直接算即可。否则就是最后一列补进来的,在之前处理最后一列的时候已经搞过了
手写了个vector,不过还是没有链表快。。。。

//Binery_Index_Tree
//http://uoj.ac/submission/297045
#include<stdio.h>
#include<cctype>
#include<cstring>
#include<algorithm>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
const int S=1<<18;
char ibuf[S],obuf[S+128],*iS,*iT,*oS=obuf,*oT=obuf+S;
#define gc (iS==iT?iT=ibuf+fread(iS=ibuf,1,S,stdin),iS==iT?EOF:*iS++:*iS++)
inline int read(){char c;
while(isspace(c=gc));int w=c&15;
while(isdigit(c=gc))w=w*10+(c&15);return w;
}
inline void flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
#define printf(...) oS>oT&&(flush(),1),oS+=sprintf(oS,__VA_ARGS__)
typedef long long ll;
const int N=3e5+5;
typedef std::pair<int,int>pii;
template<typename T>struct vec{
T*a;int n;
vec():a(0),n(0){}
inline T&operator[](const int&i){return a[i];}
inline void clear(){if(n>0)free(a),a=0;n=0;}
inline void pb(const T&x){if((n&-n)==n)a=(T*)realloc(a,(n<<1|1)*sizeof(T));a[n++]=x;}
inline T*begin(){return a;}
inline T*end(){return a+n;}
};
vec<pii>q[N];
vec<int>g[N];
int n,m,Q,c[N<<1],T,t,a[N],pre[N<<1];
inline void clr(int n){
T=n;
for(t=1;t<=T;t<<=1);t>>=1;
REP(i,1,n)c[i]=i&-i;
}
inline void inc(int p){for(;p<=T;p+=p&-p)++c[p];}
inline void dec(int p){for(;p<=T;p+=p&-p)--c[p];}
inline int ask(int k){
int x=0;
for(int p=t;p;p>>=1)if(x+p<=T&&c[x+p]<k)k-=c[x+=p];
return x+1;
}
ll ans[N<<1];
int main(){
n=read(),m=read(),Q=read();
clr(n+Q);
REP(i,1,Q){
int x=read(),y=read();
q[x].pb(pii(y,i+n));dec(y=ask(x));g[x].pb(y);
}
clr(m+Q);
REP(x,1,n){
a[0]=0;
for(pii&u:q[x]){
int y=u.first,id=u.second;
dec(a[++a[0]]=y=ask(y));
if(y<m)ans[id]=1ll*(x-1)*m+y;
else pre[id]=g[x][y-m];
}
REP(i,1,a[0])inc(a[i]);
}
REP(i,1,n)ans[i]=1ll*m*i;
REP(i,n+1,n+Q){
if(pre[i])ans[i]=ans[pre[i]];
printf("%lld\n",ans[i]);
}
return flush(),0;
}
[UOJ#334][NOIP2017]列队 平衡树/线段树/树状数组的更多相关文章
- Luogu 3960 [NOIP2017] 列队 - splay|线段树
题解 是我从来没有做过的裂点splay... 看的时候还是很懵逼的QAQ. 把最后一列的$n$个数放在一个平衡树中, 有 $n$ 个点 剩下的$n$行数, 每行都开一个平衡树,开始时每棵树中仅有$1$ ...
- NOIp2017 列队(线段树)
嘛..两年前的题目了,想起第一次参加提高组还骗了一个省二回来呢...跟同学吹了好久的... 离退役又近了一骗博客啊.. 闲聊结束. 照常化简:给定一个1-n*m编号的矩阵,每次删除一个位置,然后左边向 ...
- noip2017列队(线段树)
维护一个方阵,支持 1.删掉一个点,剩下的点先向左看齐再向前看齐 2.询问一个位置上是哪个点 $n,m,q \leq 3 \times 10^5$ sol: 我们每行前$m-1$列维护一个线段树,最后 ...
- NOIP2017 列队——平衡树
平衡树蒟蒻,敲了半天. 其实思路很简单,就是把许多个人合并成一个区间.必要的时候再拆开.(是不是和这个题的动态开点线段树有异曲同工之妙?) 每次操作最多多出来6个点. 理论上时间复杂度是nlogn,空 ...
- CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)
The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...
- NOIP2017 列队——动态开点线段树
Description: Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n×m名学生,方阵的行数为 ...
- 洛谷P3960 列队 NOIp2017 线段树/树状数组/splay
正解:动态开点线段树 解题报告: 传送门! 因为最近学主席树的时候顺便get到了动态开点线段树?刚好想起来很久很久以前就想做结果一直麻油做的这题,,,所以就做下好了QAQ 然后说下,这题有很多种方法, ...
- 【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)
http://www.lydsy.com/JudgeOnline/problem.php?id=1146 第一种做法(时间太感人): 第二种做法(rank5,好开心) ================ ...
- POJ 1804 Brainman(5种解法,好题,【暴力】,【归并排序】,【线段树单点更新】,【树状数组】,【平衡树】)
Brainman Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 10575 Accepted: 5489 Descrip ...
随机推荐
- [agc004d]salvage robot
题意: 别问我谁翻译的 虫合虫莫国的领土我们可以抽象为H*W的笼子,在这虫合土上,有若干个机器人和一个出口,其余都是空地,每次虫合虫莫会要求让所有的机器人向某个方向移动一步,当机器人移动到出口时会被虫 ...
- python3爬取全民K歌
Python3爬取全民k歌 环境 python3.5 + requests 1.通过歌曲主页链接爬取 首先打开歌曲主页,打开开发者工具(F12). 选择Network,点击播放,会发现有一个请求返回的 ...
- java+jsp+sqlserver实现简单的增删改查操作 连接数据库代码
1,网站系统开发需要掌握的技术 (1)网页设计语言,html语言css语言等 (2)Java语言 (3)数据库 (4)等 2,源程序代码 (1) 连接数据库代码 package com.jaovo.m ...
- Spring 整合Shiro:记住我
1.登录方法 /** * 执行登录操作 * * @param username * @param password * @param rememberMe * @param model * @retu ...
- codevs1281 矩阵乘法 快速幂 !!!手写乘法取模!!! 练习struct的构造函数和成员函数
对于这道题目以及我的快速幂以及我的一节半晚自习我表示无力吐槽,, 首先矩阵乘法和快速幂没必要太多说吧,,嗯没必要,,我相信没必要,,实在做不出来写两个矩阵手推一下也就能理解矩阵的顺序了,要格外注意一些 ...
- 和同事合作开发,使用局域网 git创建本地仓库
转自原文 和同事合作开发,使用局域网 git创建本地仓库 1.仓库 建一个空文件夹来做仓库,例如建为 cangku 1.1 cd 到 cangku目录下 创建远程仓库容器 mkdir mycangk ...
- ubuntu鼠标和触摸板的禁用
ubuntu鼠标和触摸板的禁用 学习了:http://www.2cto.com/os/201308/239403.html 在终端下直接执行以下命令来打开或关闭触摸板. sudo modprobe - ...
- 2015年开源项目荣登GitHub十强榜单
翻译出自:51CTO.com 开源是一个好东西,2015最振奋人心的就是swift开源. <软件开发时代>杂志(SD Times)回想了GitHub上的一些流行项目,这些项目已给开放和自由 ...
- nodejs02
Node.js没有根目录的概念,因为它根本没有任何的web容器! 让node.js提供一个静态服务,都非常难! 也就是说,node.js中,如果看见一个网址是 1127.0.0.1:3000/fang ...
- BZOJ 4269 高斯消元求线性基
思路: 最大: 所有线性基异或一下 次大: 最大的异或一下最小的线性基 搞定~ //By SiriusRen #include <cstdio> #include <algorith ...