解: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 排序的更多相关文章

  1. 洛谷——P1347 排序

    洛谷—— P1347 排序 题目描述 一个不同的值的升序排序数列指的是一个从左到右元素依次增大的序列,例如,一个有序的数列A,B,C,D 表示A<B,B<C,C<D.在这道题中,我们 ...

  2. 洛谷 P2824 [HEOI2016/TJOI2016]排序 解题报告

    P2824 [HEOI2016/TJOI2016]排序 题意: 有一个长度为\(n\)的1-n的排列\(m\)次操作 \((0,l,r)\)表示序列从\(l\)到\(r\)降序 \((1,l,r)\) ...

  3. [洛谷P2824][HEOI2016/TJOI2016]排序

    题目大意:一个全排列,两种操作: 1. $0\;l\;r:$把$[l,r]$升序排序2. $1\;l\;r:$把$[l,r]$降序排序 最后询问第$k$位是什么 题解:二分答案,把比这个数大的赋成$1 ...

  4. 洛谷P2824 [HEOI2016/TJOI2016]排序(线段树)

    传送门 这题的思路好清奇 因为只有一次查询,我们考虑二分这个值为多少 将原序列转化为一个$01$序列,如果原序列上的值大于$mid$则为$1$否则为$0$ 那么排序就可以用线段树优化,设该区间内$1$ ...

  5. 洛谷 P2824 [HEOI2016/TJOI2016]排序 (线段树合并)

    (另外:题解中有一种思路很高妙而且看上去可以适用一些其他情况的离线方法) 线段树合并&复杂度的简单说明:https://blog.csdn.net/zawedx/article/details ...

  6. 洛谷$P2824\ [HEOI2016/TJOI2016]$ 排序 线段树+二分

    正解:线段树+二分 解题报告: 传送门$QwQ$ 昂着题好神噢我$jio$得$QwQQQQQ$,,, 开始看到长得很像之前考试题的亚子,,,然后仔细康康发现不一样昂$kk$,就这里范围是$[1,n]$ ...

  7. Solution -「HEOI/TJOI 2016」「洛谷 P2824」排序

    \(\mathcal{Description}\)   Link.   给定排列 \(\{p_n\}\) 和 \(m\) 次局部排序操作,求操作完成后第 \(q\) 位的值.   \(n,m\le10 ...

  8. 洛谷 P1347 排序

    题目描述 一个不同的值的升序排序数列指的是一个从左到右元素依次增大的序列,例如,一个有序的数列A,B,C,D 表示A<B,B<C,C<D.在这道题中,我们将给你一系列形如A<B ...

  9. 洛谷P1347 排序

    这个题看到很多人写Topo排序,其实这道题第一眼看更像是一个差分约束的裸题QWQ... 令dis[x]表示x的相对大小(1是最小,n是最大),显然,对于一个关系A<B,我们有dis[A]< ...

随机推荐

  1. 打印module查看参数

    module1下的index.js require('./test2') main.js require('./module1')和require('./module2') 打印每个文件的module ...

  2. 名称空间2.0path

    Django 1点几跟2点几的区别 2.0path 是什么路径就是什么路径.第一个参数不再是正则表达式. 转换器 path的分组 <int:year> 匹配正整数 <str:year ...

  3. NOIP2016提高组复赛C 愤怒的小鸟

    题目链接:http://uoj.ac/problem/265 题目大意: 太长了不想概括... 分析: 状压DP的模板题,把所有可能的抛物线用二进制表示,然后暴力枚举所有组合,详情见代码内注释 代码如 ...

  4. element-ui 源码解析 二

    Carousel 走马灯源码解析 1. 基本原理:页面切换 页面切换使用的是 transform 2D 转换和 transition 过渡 可以看出是采用内联样式来实现的 举个栗子 <div : ...

  5. vue实例相关2

    vue data中 对象/数组 不为空,即使定义为[]/{} new Vue({ el: '#main', data: { list: [], current: {}, aa:'' } }) cons ...

  6. java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=fun2], {ExactMatcher:fDisplayName=fun2(cn.itcast.demo2.fun1)], {LeadingIdentifierMatcher:fClassName=cn.itcast.demo2.fun1,fLeadi

    Junit报的错误, 在测试方法前面没有添加注解@Test

  7. mpi4python

    转载:https://zhuanlan.zhihu.com/p/25332041 前言 在高性能计算的项目中我们通常都会使用效率更高的编译型的语言例如C.C++.Fortran等,但是由于Python ...

  8. Codeforces Round #483 Div. 1

    A:首先将p和q约分.容易发现相当于要求存在k满足bk mod q=0,也即b包含q的所有质因子.当然不能直接分解质因数,考虑每次给q除掉gcd(b,q),若能将q除至1则说明合法.但这个辣鸡题卡常, ...

  9. python成长之路一

    1,计算机基础 CPU:中央处理器,相当于人类的大脑,运算中心,控制中心. 内存:暂时储存数据,与CPU交互,8G,16G,32G,64G § 优点:读取速度快. § 缺点:容量小,造价高,断电即消失 ...

  10. bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)

    Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...