洛谷P2824 排序

解:splay + 线段树合并,分裂。
首先有个乱搞做法是外层拿splay维护,有序区间缩成splay上一个节点。内层再开个数据结构支持合并分裂有序集合。
内层我一开始想的是splay,然后就没有复杂度保证,乱搞。
后来发现可以用线段树分裂/合并来,全程复杂度一个log还能在线实时回答询问,NB!
解法二:二分答案 + 把原序列转成01序列来排序。这个我没写,但是感觉很神奇。
#include <bits/stdc++.h>
const int N = , M = ;
namespace seg {
int ls[M], rs[M], sum[M], tot, rt[N];
void insert(int p, int l, int r, int &o) {
if(!o) o = ++tot;
if(l == r) {
sum[o]++;
return;
}
int mid = (l + r) >> ;
if(p <= mid) insert(p, l, mid, ls[o]);
else insert(p, mid + , r, rs[o]);
sum[o] = sum[ls[o]] + sum[rs[o]];
return;
}
int merge(int x, int y) {
if(!x || !y) return x | y;
sum[x] += sum[y];
ls[x] = merge(ls[x], ls[y]);
rs[x] = merge(rs[x], rs[y]);
return x;
}
int getKth(int k, int l, int r, int o) {
if(l == r) return r;
int mid = (l + r) >> ;
if(k <= sum[ls[o]]) return getKth(k, l, mid, ls[o]);
else return getKth(k - sum[ls[o]], mid + , r, rs[o]);
}
void split(int o, int &x, int &y, int k) {
if(!o) {
x = y = ;
return;
}
if(!k) {
x = ;
y = o;
return;
}
if(k == sum[o]) {
x = o;
y = ;
return;
}
if(k <= sum[ls[o]]) {
x = ++tot;
y = o;
split(ls[o], ls[x], ls[y], k);
}
else {
y = ++tot;
x = o;
split(rs[o], rs[x], rs[y], k - sum[ls[o]]);
}
sum[x] = sum[ls[x]] + sum[rs[x]];
sum[y] = sum[ls[y]] + sum[rs[y]];
return;
}
void out(int l, int r, int o) {
if(!o || !sum[o]) return;
if(l == r) {
printf("%d ", r);
return;
}
int mid = (l + r) >> ;
out(l, mid, ls[o]);
out(mid + , r, rs[o]);
return;
}
}
/// ---------
int fa[N], s[N][], len[N], lpos[N], rpos[N], siz[N], type[N], root, tot, n, a[N];
std::stack<int> Bin;
int stk[N], top;
inline void pushup(int x) {
siz[x] = siz[s[x][]] + siz[s[x][]] + len[x];
//printf("pushup [%d %d] %d + %d + %d \n", lpos[x], rpos[x], siz[s[x][0]], len[x], siz[s[x][1]]);
if(!fa[x]) root = x;
return;
}
inline void pushdown(int x) {
return;
}
inline void rotate(int x) {
int y = fa[x];
int z = fa[y];
bool f = (s[y][] == x);
fa[x] = z;
if(z) {
s[z][s[z][] == y] = x;
}
s[y][f] = s[x][!f];
if(s[x][!f]) {
fa[s[x][!f]] = y;
}
s[x][!f] = y;
fa[y] = x;
pushup(y);
return;
}
inline void splay(int x, int g = ) {
int y = x;
stk[top = ] = y;
while(fa[y]) {
y = fa[y];
stk[++top] = y;
}
while(top) {
pushdown(stk[top]);
top--;
}
y = fa[x];
int z = fa[y];
while(y != g) {
if(z != g) {
(s[z][] == y) ^ (s[y][] == x) ?
rotate(x) : rotate(y);
}
rotate(x);
y = fa[x];
z = fa[y];
}
pushup(x);
return;
}
void out(int x = root) {
pushdown(x);
if(s[x][]) {
out(s[x][]);
}
printf("[%d %d] ", lpos[x], rpos[x]);
printf("rt = %d : ", seg::rt[x]);
seg::out(, n, seg::rt[x]);
puts("");
if(s[x][]) {
out(s[x][]);
}
return;
}
inline int np(int l, int r, int f, int tp) {
int x;
if(Bin.size()) {
x = Bin.top();
seg::rt[x] = ;
Bin.pop();
}
else x = ++tot;
fa[x] = f;
s[x][] = s[x][] = ;
lpos[x] = l;
rpos[x] = r;
siz[x] = len[x] = r - l + ;
type[x] = tp;
return x;
}
inline int getRP() {
pushdown(root);
int p = s[root][];
pushdown(p);
while(s[p][]) {
p = s[p][];
pushdown(p);
}
return p;
}
inline int getLP() {
pushdown(root);
int p = s[root][];
pushdown(p);
while(s[p][]) {
p = s[p][];
pushdown(p);
}
return p;
}
inline int getPbyR(int k) {
k++;
int p = root;
while() {
//printf("p : [%d %d] %d -> [%d %d] %d [%d %d] %d \n", lpos[p], rpos[p], siz[p], lpos[s[p][0]], rpos[s[p][0]], siz[s[p][0]], lpos[s[p][1]], rpos[s[p][1]], siz[s[p][1]]);
pushdown(p);
if(k <= siz[s[p][]]) {
p = s[p][];
}
else if(k <= siz[s[p][]] + len[p]) {
break;
}
else {
k -= siz[s[p][]] + len[p];
p = s[p][];
}
}
/// p
splay(p);
return p;
}
inline int split(int x, int k) { /* [lpos[x], k] [k + 1, rpos[x]] return left */
int A, B;
splay(x);
int y = getRP();
splay(y, x);
if(type[x] == ) {
seg::split(seg::rt[x], A, B, k);
int z = np(lpos[x] + k, rpos[x], y, type[x]);
rpos[x] = lpos[x] + k - ;
len[x] = rpos[x] - lpos[x] + ;
seg::rt[z] = B;
seg::rt[x] = A;
s[y][] = z;
pushup(y);
pushup(x);
}
else {
seg::split(seg::rt[x], A, B, len[x] - k);
int z = np(lpos[x] + k, rpos[x], y, type[x]);
rpos[x] = lpos[x] + k - ;
len[x] = rpos[x] - lpos[x] + ;
seg::rt[z] = A;
seg::rt[x] = B;
s[y][] = z;
pushup(y);
pushup(x);
}
return x;
}
void dfs(int x, int rt) {
if(s[x][]) {
dfs(s[x][], rt);
}
if(s[x][]) {
dfs(s[x][], rt);
}
if(x != rt) {
seg::rt[rt] = seg::merge(seg::rt[rt], seg::rt[x]);
Bin.push(x);
}
return;
}
inline void Sort(int L, int R, int f) { /* 0 up 1 down */
int x = getPbyR(L);
//printf("x %d [%d %d] y %d [%d %d] \n", x, lpos[x], rpos[x], y, lpos[y], rpos[y]);
if(lpos[x] != L) {
x = split(x, L - lpos[x]);
splay(x);
x = getRP();
}
int y = getPbyR(R);
//printf("x %d [%d %d] y %d [%d %d] \n", x, lpos[x], rpos[x], y, lpos[y], rpos[y]);
if(rpos[y] != R) {
y = split(y, R - lpos[y] + );
}
// merge [x, y]
//printf("x %d [%d %d] y %d [%d %d] \n", x, lpos[x], rpos[x], y, lpos[y], rpos[y]);
splay(x);
int A = getLP();
splay(y);
int B = getRP();
splay(B);
splay(A, B);
/// s[A][1]
x = s[A][];
dfs(x, x);
lpos[x] = L;
rpos[x] = R;
siz[x] = len[x] = R - L + ;
type[x] = f;
s[x][] = s[x][] = ;
pushup(A);
pushup(B);
return;
}
/*
5 5
1 2 3 4 5
1 2 3
1 4 5
1 1 4
0 2 5
0 3 4
1
------------
*/
inline int ask(int p) {
int x = getPbyR(p);
if(type[x] == ) {
int k = p - lpos[x] + ;
return seg::getKth(k, , n, seg::rt[x]);
}
else {
int k = p - lpos[x] + ;
k = len[x] - k + ;
return seg::getKth(k, , n, seg::rt[x]);
}
}
int build(int l, int r, int f) {
int mid = (l + r) >> ;
int x = np(mid, mid, f, );
if(mid && mid <= n) seg::insert(a[mid], , n, seg::rt[x]);
if(l < mid) s[x][] = build(l, mid - , x);
if(mid < r) s[x][] = build(mid + , r, x);
pushup(x);
return x;
}
int main() {
int m;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
}
/// build
root = build(, n + , );
//out(), puts("");
for(int i = , f, l, r; i <= m; i++) {
scanf("%d%d%d", &f, &l, &r);
Sort(l, r, f);
//out(), puts("");
}
int q;
scanf("%d", &q);
int t = ask(q);
printf("%d\n", t);
return ;
}
AC代码
这题调的时候splay出了大约10个锅,从没写过的线段树分裂一次写对......
线段树分裂,把前k小分成一个,后面分成另一个。实现类似fhqtreap,不过要新开节点。
洛谷P2824 排序的更多相关文章
- 洛谷——P1347 排序
洛谷—— P1347 排序 题目描述 一个不同的值的升序排序数列指的是一个从左到右元素依次增大的序列,例如,一个有序的数列A,B,C,D 表示A<B,B<C,C<D.在这道题中,我们 ...
- 洛谷 P2824 [HEOI2016/TJOI2016]排序 解题报告
P2824 [HEOI2016/TJOI2016]排序 题意: 有一个长度为\(n\)的1-n的排列\(m\)次操作 \((0,l,r)\)表示序列从\(l\)到\(r\)降序 \((1,l,r)\) ...
- [洛谷P2824][HEOI2016/TJOI2016]排序
题目大意:一个全排列,两种操作: 1. $0\;l\;r:$把$[l,r]$升序排序2. $1\;l\;r:$把$[l,r]$降序排序 最后询问第$k$位是什么 题解:二分答案,把比这个数大的赋成$1 ...
- 洛谷P2824 [HEOI2016/TJOI2016]排序(线段树)
传送门 这题的思路好清奇 因为只有一次查询,我们考虑二分这个值为多少 将原序列转化为一个$01$序列,如果原序列上的值大于$mid$则为$1$否则为$0$ 那么排序就可以用线段树优化,设该区间内$1$ ...
- 洛谷 P2824 [HEOI2016/TJOI2016]排序 (线段树合并)
(另外:题解中有一种思路很高妙而且看上去可以适用一些其他情况的离线方法) 线段树合并&复杂度的简单说明:https://blog.csdn.net/zawedx/article/details ...
- 洛谷$P2824\ [HEOI2016/TJOI2016]$ 排序 线段树+二分
正解:线段树+二分 解题报告: 传送门$QwQ$ 昂着题好神噢我$jio$得$QwQQQQQ$,,, 开始看到长得很像之前考试题的亚子,,,然后仔细康康发现不一样昂$kk$,就这里范围是$[1,n]$ ...
- Solution -「HEOI/TJOI 2016」「洛谷 P2824」排序
\(\mathcal{Description}\) Link. 给定排列 \(\{p_n\}\) 和 \(m\) 次局部排序操作,求操作完成后第 \(q\) 位的值. \(n,m\le10 ...
- 洛谷 P1347 排序
题目描述 一个不同的值的升序排序数列指的是一个从左到右元素依次增大的序列,例如,一个有序的数列A,B,C,D 表示A<B,B<C,C<D.在这道题中,我们将给你一系列形如A<B ...
- 洛谷P1347 排序
这个题看到很多人写Topo排序,其实这道题第一眼看更像是一个差分约束的裸题QWQ... 令dis[x]表示x的相对大小(1是最小,n是最大),显然,对于一个关系A<B,我们有dis[A]< ...
随机推荐
- .Net MVC4 log4net的配置
一.首先在使用log4net记录日志的时候,我们要引用log4net.dll文件 二.在web.config中添加一下配置代码 <configSections> <!-- For m ...
- hadoop分布式系统架构详解
hadoop 简单来说就是用 java写的分布式 ,处理大数据的框架,主要思想是 “分组合并” 思想. 分组:比如 有一个大型数据,那么他就会将这个数据按照算法分成多份,每份存储在 从属主机上,并且在 ...
- python之路--MySQL多表查询
一 介绍 我们在写项目的时候一般都会建一个数据库,数据库里面会存很多的表,不可能把所有的数据都放在一张表里,因为分表来存数据节省空间,数据的组织结构更清晰,解耦和程度更高,但是这些表本质上还不是一个整 ...
- Sqoop 使用详解(内含对官方文档的解析)
Sqoop 是 Cloudera 公司创造的一个数据同步工具,现在已经完全开源了. 目前已经是 hadoop 生态环境中数据迁移的首选,另外还有 ali 开发的 DataX 属于同类型工具,由于社区的 ...
- Golang的方法传递值应该注意的地方
其实最近看了不少Golang接口以及方法的阐述都有一个地方没说得特别明白.就是在Golang编译隐式转换传递给方法使用的时候,和调用函数时的区别. 我们都知道,在我们为一个类型变量申明了一个方法的时候 ...
- shell中的>,2>&1,&>file 解析记录
0 表示标准输入1 表示标准输出2 表示标准错误输出> 默认为标准输出重定向,与 1> 相同2>&1 意思是把 标准错误输出 重定向到 标准输出.&> ...
- Object...与Object[]使用的一点区别和记录
Object是所有类的基类 简述: Object ...objects(称为可变个数的形参)这种参数定义是在不确定方法参数的情况下的一种多态表现形式.Java可变参数,即这个方法可以传递多个参数,这个 ...
- RabbitMQ在Ubuntu 16.04下的安装与配置
安装执行如下命令: echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d ...
- WhiteHat Contest 11 : re1-100
ELF文件,运行一下是要求输密码 die查了一下无壳 直接拖入ida 可以发现 这是它的判断函数 也就是说输入的总长度是42位第一个字符是123也就是0x7b 也就是'{'然后10位是"53 ...
- NPOI 上传Excel功能(三)
4.验证Excel并上传 using DC.BE.Business.SAS; using DC.BE.Business.SYS; using DC.BE.Entity.SAS; using DC.BE ...