洛谷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]< ...
随机推荐
- js中的call、apply、bind
在js中每个函数都包含两个非继承而来的方法:call()和apply() call和apply的作用都是在特定的作用域中将函数绑定到另外一个对象上去运行,即可以用来重新定义函数的执行环境,两者仅在定义 ...
- tensorflow实现基于LSTM的文本分类方法
tensorflow实现基于LSTM的文本分类方法 作者:u010223750 引言 学习一段时间的tensor flow之后,想找个项目试试手,然后想起了之前在看Theano教程中的一个文本分类的实 ...
- EXAMPLE FOR PEEWEE 多姿势使用 PEEWEE
使用 PEEWEE 断断续续的差不多已经三个年头了,但是没有像这次使用这么多的特性和功能,所以这次一并记录一下,需要注意的地方和一些使用细节,之后使用起来可能会更方便. 因为是使用的 SQLAched ...
- docker 列出每个容器的IP
抄来的...找不到出处了. 常用方法有两种 docker inspect 容器ID | grep IPAddress 方法二 查看docker name: sudo docker inspect ...
- flask 保存文件到 七牛云
上篇文章队长讲述了如何把前端上传的文件保存到本地项目目录 本篇 讲述一下把前端上传的文件保存到 第三方存储(七牛云) 七牛云相关步骤思路: 首先 进去七牛云官网,注册并实名认证来获取一个七牛云账号和存 ...
- 一、ABP框架框架摘要
ABP框架几点说明: 一.什么是ABP ABP是一个建立在最新的ASP.NET的MVC和Web API技术的应用框架.它可以很容易地使用依赖注入.日志记录.验证.异常处理.本地化等,也使用流行的框架和 ...
- nginx 负载均衡(默认算法)
使用 nginx 的upstream模块只需要几步就可以实现一个负载均衡: 在 nginx 配置文件中添加两个server server { listen ; server_name 192.168. ...
- JSON in SQL Server 2016
JSON functions in SQL Server enable you to analyze and query JSON data, transform JSON to relational ...
- codeforces-962-c
题意:给你一个数,问从中删除某几位数字后重新组成的数字是否是某个数的平方: 解题思路:数据小,dfs直接搜,每位数只有两种选择,要或者不要 #include<iostream> #incl ...
- Codeforces264 B. Good Sequences
Codeforces题号:#264B 出处: Codeforces 主要算法:DP 难度:4.8 思路分析: 这题DP太难了…… 最终的解法是,令f[i]表示存在因子i的一个数作为子序列结尾的子序列的 ...