个人感觉可能是最不需要脑子写的方法

不过也不太好调

就是用一个普通的线段树维护这个序列,但是对于线段树的每一个区间,再开一个动态开点的权值线段树,里面存储这个区间所有元素值

单点修改只会涉及到log棵权值线段树的单点修改(不用打lazy太棒了 log^2

查询区间内x的排名相当于查询区间内<x的数的个数+1,我们把区间分成log个外层线段树上的区间,然后在每个权值线段树上统计即可,复杂度log^2

查询排名为x的数比较麻烦,我们直接二分,复杂度log^3

查询前驱后继:由于线段树维护的区间,总区间是把这log个区间相加,所以我们再每个权值线段树查询下前驱后继再合并就行,前驱取max,后继取min

至于怎么查询,可以在线段树上二分

代码写的特别乱...

#include <cstdio>
#include <functional>
using namespace std; int l[17000010], r[17000010], tree[17000010], tot;
int rt[200010], init[50010], fuck = 100000000;
int s[10000010], top; int n, m; void chenge(int &x, int cl, int cr, int pos, int val)
{
if (x == 0)
{
if (top > 0) x = s[top--];
else x = ++tot;
}
if (tot % 100000 == 0) fprintf(stderr, "(%d, %d)\n", tot, top);
if (cl == cr) {tree[x] += val; if (tree[x] == 0) s[++top] = x, x = 0; return; }
int mid = (cl + cr) / 2;
if (pos > mid) chenge(r[x], mid + 1, cr, pos, val);
else chenge(l[x], cl, mid, pos, val);
tree[x] = tree[l[x]] + tree[r[x]];
if (l[x] == 0 && r[x] == 0) { s[++top] = x, x = 0; }
} int query(int x, int cl, int cr, int pos)
{
if (x == 0 || cl == cr) return 0;
int mid = (cl + cr) / 2;
if (pos > mid)
return tree[l[x]] + query(r[x], mid + 1, cr, pos);
else return query(l[x], cl, mid, pos);
} int qrange(int x, int cl, int cr, int L, int R)
{
if (x == 0) return 0;
if (R < cl || cr < L) return 0;
if (L <= cl && cr <= R) return tree[x];
int mid = (cl + cr) / 2;
return qrange(l[x], cl, mid, L, R) + qrange(r[x], mid + 1, cr, L, R);
} int getnumber(int x, int cl, int cr, int rank)
{
if (cl == cr) { return cl; }
int mid = (cl + cr) / 2;
if (rank <= tree[l[x]]) return getnumber(l[x], cl, mid, rank);
else return getnumber(r[x], mid + 1, cr, rank - tree[l[x]]);
} int getnumber2(int x, int cl, int cr, int rank)
{
if (cl == cr) { return cl; }
int mid = (cl + cr) / 2;
if (rank <= tree[r[x]]) return getnumber2(r[x], mid + 1, cr, rank);
else return getnumber2(l[x], cl, mid, rank - tree[r[x]]);
} int getprev(int rt, int pos)
{
int tot = qrange(rt, 0, fuck, 0, pos - 1); // [1, pos - 1]内数的个数
if (tot == 0) return -2147483647;
return getnumber(rt, 0, fuck, tot);
} int getnext(int rt, int pos)
{
int tot = qrange(rt, 0, fuck, pos + 1, fuck);
if (tot == 0) return 2147483647;
return getnumber2(rt, 0, fuck, tot);
} //---- 外面线段树 void build(int x, int l, int r)
{
for (int i = l; i <= r; i++)
chenge(rt[x], 0, fuck, init[i], 1);
if (l == r) return;
int mid = (l + r) / 2;
build(x * 2, l, mid);
build(x * 2 + 1, mid + 1, r);
} int qrank(int x, int cl, int cr, int L, int R, int k)
{
if (R < cl || cr < L) return 0;
if (L <= cl && cr <= R) return query(rt[x], 0, fuck, k);
int mid = (cl + cr) / 2;
return qrank(x * 2, cl, mid, L, R, k) + qrank(x * 2 + 1, mid + 1, cr, L, R, k);
} void change(int x, int cl, int cr, int pos, int val)
{
chenge(rt[x], 0, fuck, init[pos], -1);
chenge(rt[x], 0, fuck, val, 1);
if (cl == cr) return;
int mid = (cl + cr) / 2;
if (pos > mid) change(x * 2 + 1, mid + 1, cr, pos, val);
else change(x * 2, cl, mid, pos, val);
} int qprev(int x, int cl, int cr, int L, int R, int k)
{
if (R < cl || cr < L) return -2147483647;
if (L <= cl && cr <= R)
{
int res = getprev(rt[x], k);
return res;
}
int mid = (cl + cr) / 2;
return max(qprev(x * 2, cl, mid, L, R, k), qprev(x * 2 + 1, mid + 1, cr, L, R, k));
} int qnext(int x, int cl, int cr, int L, int R, int k)
{
if (R < cl || cr < L) return 2147483647;
if (L <= cl && cr <= R) return getnext(rt[x], k);
int mid = (cl + cr) / 2;
return min(qnext(x * 2, cl, mid, L, R, k), qnext(x * 2 + 1, mid + 1, cr, L, R, k));
} int main()
{
// printf("%f\n", (3 * sizeof(l) + sizeof(s) + sizeof(rt)) / 1000000.);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &init[i]);
build(1, 1, n);
for (int opd, l, r, k, i = 1; i <= m; i++)
{
scanf("%d%d%d", &opd, &l, &r);
if (opd != 3) scanf("%d", &k);
if (opd == 1)
{
printf("%d\n", qrank(1, 1, n, l, r, k) + 1);
}
if (opd == 2) // query值<k的最大一撮数中最小的一个
{
// for (int i = 0; i <= 10; i++) printf("query(%d) = %d\n", i, qrank(1, 1, n, l, r, i));
int cl = 0, cr = 100000000;
while (cl < cr)
{
int mid = (cl + cr + 1) / 2;
if (qrank(1, 1, n, l, r, mid) < k) cl = mid;
else cr = mid - 1;
}
// int ans = qrank(1, 1, n, l, r, cl);
// cl = 0, cr = 100000000;
// while (cl < cr)
// {
// int mid = (cl + cr) / 2;
// if (qrank(1, 1, n, l, r, mid) >= ans) cr = mid;
// else cl = mid + 1;
// }
printf("%d\n", cl);
}
if (opd == 3)
{
change(1, 1, n, l, r);
init[l] = r;
}
if (opd == 4)
{
printf("%d\n", qprev(1, 1, n, l, r, k));
}
if (opd == 5)
{
printf("%d\n", qnext(1, 1, n, l, r, k));
}
}
return 0;
}

luogu3380 树套树之线段树套线段树的更多相关文章

  1. 「luogu3380」【模板】二逼平衡树(树套树)

    「luogu3380」[模板]二逼平衡树(树套树) 传送门 我写的树套树--线段树套平衡树. 线段树上的每一个节点都是一棵 \(\text{FHQ Treap}\) ,然后我们就可以根据平衡树的基本操 ...

  2. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

  3. 树剖+线段树||树链剖分||BZOJ1984||Luogu4315||月下“毛景树”

    题面:月下“毛景树” 题解:是道很裸的树剖,但处理的细节有点多(其实是自己线段树没学好).用一个Dfs把边权下移到点权,用E数组记录哪些边被用到了:前三个更新的操作都可以合并起来,可以发现a到b节点间 ...

  4. 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)

    Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...

  5. BZOJ4881 线段游戏(二分图+树状数组/动态规划+线段树)

    相当于将线段划分成两个集合使集合内线段不相交,并且可以发现线段相交等价于逆序对.也即要将原序列划分成两个单增序列.由dilworth定理,如果存在长度>=3的单减子序列,无解,可以先判掉. 这个 ...

  6. 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)

    [BZOJ4817]树点涂色(LCT,线段树,树链剖分) 题面 BZOJ Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义 ...

  7. [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)

    [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...

  8. 「雅礼集训 2017 Day2」线段游戏(线段树懒标记“启发式下传”,李超树)

    题面 题解 加入一条线段,可以把它转化为在[L,R]区间内加一条线 y=ax+b (如果原线段与y轴平行,就相当于在{x1}处加一条线 y=max(y1,y2)) 我们可以把它加到线段树上,线段树上每 ...

  9. 树链剖分 - Luogu 3384【模板】树链剖分

    [模板]树链剖分 题目描述 已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操 ...

  10. 数据结构--树(遍历,红黑,B树)

    平时接触树还比较少,写一篇博文来积累一下树的相关知识. 很早之前在数据结构里面学的树的遍历. 前序遍历:根节点->左子树->右子树 中序遍历:左子树->根节点->右子树 后序遍 ...

随机推荐

  1. Struts旅程(六)Struts页面转发控制ActionForward和ActionMapping

    转自:https://blog.csdn.net/lovesummerforever/article/details/19125933

  2. sqlserver 使用维护计划备份

    https://www.cnblogs.com/teafree/p/4240040.html

  3. eclipse中创建maven web项目

    本文主要说明将maven web项目转成eclipse支持的web项目. 创建一个maven项目设置打包类型为war则其为web项目 结构如下 将mavenweb项目转成eclipse识别的web项目 ...

  4. win10 更换秘钥报错:拒绝访问:所请求的操作需要提升特权

    直接打开cmd执行换秘钥的命令: slmgr /ipk VK7JG-NPHTM-C97JM-9MPGT-3V66T slmgr /skms kms.xspace.in slmgr /ato 报错如图: ...

  5. tab下拉菜单

    这个想法早就有的 (写tab下拉菜单)就觉得自己对js不是很熟   所以一直没有写 花了不少时间 <!DOCTYPE html> <html> <head> < ...

  6. Shell表达式,如${file##*/}

    Shell表达式,如${file##*/} 2017年10月26日 15:24:40 阅读数:343 今天看一个脚本文件的时候有一些地方不太懂,找了一篇文章看了一些,觉得不错,保留下来. 假设我们定义 ...

  7. Java并发之FutureTask

    FutureTask实现了Runnable和Future接口,是一个可取消的异步任务.利用开始和取消计算的方法.查询计算是否完成的方法和获取计算结果的方法,此类提供了对 Future 的基本实现.仅在 ...

  8. 多线程学习-基础(七)sleep()和wait()的区别

    一.sleep()和wait()的区别共同点:1.他们都是在多线程的环境下,都可以在程序的调用出阻塞指定的毫秒,然后继续往后执行(在当前线程再次拿到cpu的执行权之后).2.wait()和sleep( ...

  9. css 隐藏html元素的方法

    1.常见方法 display:none 这个方法的问题是 元素被隐藏了 同时该元素不占位置了,应该也可以说该元素没有高度和宽度了 2.常见方法 visibility: hidden; 这个方法和dis ...

  10. c# dictionary,list排序

    Dictionary Key排序 Dictionary<string, string> dct= new Dictionary<string, string>(); Dicti ...