luogu3380 树套树之线段树套线段树
个人感觉可能是最不需要脑子写的方法
不过也不太好调
就是用一个普通的线段树维护这个序列,但是对于线段树的每一个区间,再开一个动态开点的权值线段树,里面存储这个区间所有元素值
单点修改只会涉及到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 树套树之线段树套线段树的更多相关文章
- 「luogu3380」【模板】二逼平衡树(树套树)
「luogu3380」[模板]二逼平衡树(树套树) 传送门 我写的树套树--线段树套平衡树. 线段树上的每一个节点都是一棵 \(\text{FHQ Treap}\) ,然后我们就可以根据平衡树的基本操 ...
- 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题
“队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄> 线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...
- 树剖+线段树||树链剖分||BZOJ1984||Luogu4315||月下“毛景树”
题面:月下“毛景树” 题解:是道很裸的树剖,但处理的细节有点多(其实是自己线段树没学好).用一个Dfs把边权下移到点权,用E数组记录哪些边被用到了:前三个更新的操作都可以合并起来,可以发现a到b节点间 ...
- 计蒜客 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 ...
- BZOJ4881 线段游戏(二分图+树状数组/动态规划+线段树)
相当于将线段划分成两个集合使集合内线段不相交,并且可以发现线段相交等价于逆序对.也即要将原序列划分成两个单增序列.由dilworth定理,如果存在长度>=3的单减子序列,无解,可以先判掉. 这个 ...
- 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
[BZOJ4817]树点涂色(LCT,线段树,树链剖分) 题面 BZOJ Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义 ...
- [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)
[51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...
- 「雅礼集训 2017 Day2」线段游戏(线段树懒标记“启发式下传”,李超树)
题面 题解 加入一条线段,可以把它转化为在[L,R]区间内加一条线 y=ax+b (如果原线段与y轴平行,就相当于在{x1}处加一条线 y=max(y1,y2)) 我们可以把它加到线段树上,线段树上每 ...
- 树链剖分 - Luogu 3384【模板】树链剖分
[模板]树链剖分 题目描述 已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操 ...
- 数据结构--树(遍历,红黑,B树)
平时接触树还比较少,写一篇博文来积累一下树的相关知识. 很早之前在数据结构里面学的树的遍历. 前序遍历:根节点->左子树->右子树 中序遍历:左子树->根节点->右子树 后序遍 ...
随机推荐
- Struts旅程(六)Struts页面转发控制ActionForward和ActionMapping
转自:https://blog.csdn.net/lovesummerforever/article/details/19125933
- sqlserver 使用维护计划备份
https://www.cnblogs.com/teafree/p/4240040.html
- eclipse中创建maven web项目
本文主要说明将maven web项目转成eclipse支持的web项目. 创建一个maven项目设置打包类型为war则其为web项目 结构如下 将mavenweb项目转成eclipse识别的web项目 ...
- win10 更换秘钥报错:拒绝访问:所请求的操作需要提升特权
直接打开cmd执行换秘钥的命令: slmgr /ipk VK7JG-NPHTM-C97JM-9MPGT-3V66T slmgr /skms kms.xspace.in slmgr /ato 报错如图: ...
- tab下拉菜单
这个想法早就有的 (写tab下拉菜单)就觉得自己对js不是很熟 所以一直没有写 花了不少时间 <!DOCTYPE html> <html> <head> < ...
- Shell表达式,如${file##*/}
Shell表达式,如${file##*/} 2017年10月26日 15:24:40 阅读数:343 今天看一个脚本文件的时候有一些地方不太懂,找了一篇文章看了一些,觉得不错,保留下来. 假设我们定义 ...
- Java并发之FutureTask
FutureTask实现了Runnable和Future接口,是一个可取消的异步任务.利用开始和取消计算的方法.查询计算是否完成的方法和获取计算结果的方法,此类提供了对 Future 的基本实现.仅在 ...
- 多线程学习-基础(七)sleep()和wait()的区别
一.sleep()和wait()的区别共同点:1.他们都是在多线程的环境下,都可以在程序的调用出阻塞指定的毫秒,然后继续往后执行(在当前线程再次拿到cpu的执行权之后).2.wait()和sleep( ...
- css 隐藏html元素的方法
1.常见方法 display:none 这个方法的问题是 元素被隐藏了 同时该元素不占位置了,应该也可以说该元素没有高度和宽度了 2.常见方法 visibility: hidden; 这个方法和dis ...
- c# dictionary,list排序
Dictionary Key排序 Dictionary<string, string> dct= new Dictionary<string, string>(); Dicti ...