【知识】树套树

news/2024/12/15 20:43:36/文章来源:https://www.cnblogs.com/fanrunze/p/18608677

树套树

顾名思义,就是一个树套着一个树。

例如:线段树套平衡树,线段树中的每个节点的区间用平衡树维护。

常用:

  • 外层:线段树,树状数组
  • 内层:平衡树,线段树。(一般可以用 STL

例题:

  • AcWing 2488

    没啥好说的,线段树套 set

    #include <bits/stdc++.h>
    using namespace std;const int N = 50005, M = N << 2;
    const int INF = 0x3f3f3f3f;
    int n, m;
    struct Tree{int l, r;multiset<int> s;
    } tr[M];
    int w[N];void build(int u,int l,int r){tr[u] = {l, r};tr[u].s.insert(-INF), tr[u].s.insert(INF);for (int i = l; i <= r;i++)tr[u].s.insert(w[i]);int mid = l + r >> 1;if(l==r)return;build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    }void change(int u,int p,int x){tr[u].s.erase(tr[u].s.find(w[p]));tr[u].s.insert(x);if(tr[u].l==tr[u].r)return;int mid = tr[u].l + tr[u].r >> 1;if(p<=mid)change(u << 1, p, x);elsechange(u << 1 | 1, p, x);
    }int query(int u,int a,int b,int x){if(tr[u].l>=a&&tr[u].r<=b){auto it = tr[u].s.lower_bound(x);--it;return *it;}int mid = tr[u].l + tr[u].r >> 1;int res = -INF;if(a<=mid)res = max(res, query(u << 1, a, b, x));if(b>mid)res = max(res, query(u << 1 | 1, a, b, x));return res;
    }
    int main(){cin >> n >> m;for (int i = 1; i <= n;i++)cin >> w[i];build(1, 1, n);while(m--){int op, a, b, x;cin >> op;if(op==x){cin >> a >> x;change(1, a, x);w[a] = x;}else{cin >> a >> b >> x;cout << query(1, a, b, x) << endl;}}return 0;
    }
    
  • P3380 【模板】树套树

    #include <bits/stdc++.h>
    using namespace std;const int N = 2000005, INF = 2147483647;
    int n, m;
    struct Node{int s[2], p, v;int sz;void init(int _v,int _p){v = _v, p = _p;sz = 1;}
    } tr[N];
    int L[N], R[N], T[N], idx;
    int w[N];void pushup(int x){tr[x].sz = tr[tr[x].s[0]].sz + tr[tr[x].s[1]].sz + 1;
    }void rotate(int x){int y = tr[x].p, z = tr[y].p;int k = tr[y].s[1] == x;tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z;tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;tr[x].s[k ^ 1] = y, tr[y].p = x;pushup(y), pushup(x);
    }void splay(int &root,int x,int k){while(tr[x].p!=k){int y = tr[x].p, z = tr[y].p;if(z!=k)if((tr[y].s[1]==x)^(tr[z].s[1]==y))rotate(x);elserotate(y);rotate(x);}if(!k)root = x;
    }void insert(int &root,int v){int u = root, p = 0;while(u)p = u, u = tr[u].s[v > tr[u].v];u = ++idx;if(p)tr[p].s[v > tr[p].v] = u;tr[u].init(v, p);splay(root, u, 0);
    }int get_k(int root,int v){int u = root, res = 0;while(u){if(tr[u].v<v)res += tr[tr[u].s[0]].sz + 1, u = tr[u].s[1];elseu = tr[u].s[0];}return res;
    }void update(int &root,int x,int y){int u = root;while(u){if(tr[u].v==x)break;if(tr[u].v<x)u = tr[u].s[1];elseu = tr[u].s[0];}splay(root, u, 0);int l = tr[u].s[0], r = tr[u].s[1];while(tr[l].s[1])l = tr[l].s[1];while(tr[r].s[0])r = tr[r].s[0];splay(root, l, 0), splay(root, r, l);tr[r].s[0] = 0;pushup(l), pushup(r);insert(root, y);
    }void build(int u,int l,int r){L[u] = l, R[u] = r;insert(T[u], INF), insert(T[u], -INF);for (int i = l; i <= r;i++)insert(T[u], w[i]);if(l==r)return;int mid = l + r >> 1;build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    }int query(int u,int a,int b,int x){if(L[u]>=a&&R[u]<=b)return get_k(T[u], x) - 1;int mid = L[u] + R[u] >> 1;int res = 0;if(a<=mid)res += query(u<<1, a, b, x);if(b>mid)res += query(u << 1 | 1, a, b, x);return res;
    }void change(int u,int p,int x){update(T[u], w[p], x);if(L[u]==R[u])return;int mid = L[u] + R[u] >> 1;if(p<=mid)change(u << 1, p, x);elsechange(u << 1 | 1, p, x);
    }int get_pre(int root,int v){int u = root, res = -INF;while(u){if(tr[u].v<v)res = max(res, tr[u].v), u = tr[u].s[1];elseu = tr[u].s[0];}return res;
    }int get_suc(int root,int v){int u = root, res = INF;while(u){if(tr[u].v>v)res = min(res, tr[u].v), u = tr[u].s[0];elseu = tr[u].s[1];}return res;
    }
    int query_pre(int u,int a,int b,int x){if(L[u]>=a&&R[u]<=b)return get_pre(T[u], x);int mid = L[u] + R[u] >> 1;int res = -INF;if(a<=mid)res = max(res, query_pre(u << 1, a, b, x));if(b>mid)res = max(res, query_pre(u << 1 | 1, a, b, x));return res;
    }int query_suc(int u,int a,int b,int x){if(L[u]>=a&&R[u]<=b)return get_suc(T[u], x);int mid = L[u] + R[u] >> 1;int res = INF;if(a<=mid)res = min(res, query_suc(u << 1, a, b, x));if(b>mid)res = min(res, query_suc(u << 1 | 1, a, b, x));return res;
    }int main(){cin >> n >> m;for (int i = 1; i <= n;i++)cin >> w[i];build(1, 1, n);while(m--){int op, a, b, x;cin >> op;if(op==1){cin >> a >> b >> x;cout << query(1, a, b, x) +1 << endl;}else if(op==2){cin >> a >> b >> x;int l = 0, r = 1e8;while(l<r){int mid = l + r + 1 >> 1;if(query(1,a,b,mid)+1<=x)l = mid;elser = mid - 1;}cout << r << endl;}else if(op==3){cin >> a >> x;change(1, a, x);w[a] = x;}else if(op==4){cin >> a >> b >> x;cout << query_pre(1, a, b, x) << endl;}else{cin >> a >> b >> x;cout << query_suc(1, a, b, x) << endl;}}return 0;
    }
    
  • P3332 [ZJOI2013] K大数查询

    考虑值域线段树套线段树。

    Tips:标记持久化,动态开店线段树。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <vector>using namespace std;typedef long long LL;const int N = 50010, P = N * 17 * 17, M = N * 4;int n, m;
    struct Tree
    {int l, r;LL sum, add;
    }tr[P];
    int L[M], R[M], T[M], idx;
    struct Query
    {int op, a, b, c;
    }q[N];
    vector<int> nums;int get(int x)
    {return lower_bound(nums.begin(), nums.end(), x) - nums.begin();
    }void build(int u, int l, int r)
    {L[u] = l, R[u] = r, T[u] = ++ idx;if (l == r) return;int mid = l + r >> 1;build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    }int intersection(int a, int b, int c, int d)
    {return min(b, d) - max(a, c) + 1;
    }void update(int u, int l, int r, int pl, int pr)
    {tr[u].sum += intersection(l, r, pl, pr);if (l >= pl && r <= pr){tr[u].add ++ ;return;}int mid = l + r >> 1;if (pl <= mid){if (!tr[u].l) tr[u].l = ++ idx;update(tr[u].l, l, mid, pl, pr);}if (pr > mid){if (!tr[u].r) tr[u].r = ++ idx;update(tr[u].r, mid + 1, r, pl, pr);}
    }void change(int u, int a, int b, int c)
    {update(T[u], 1, n, a, b);if (L[u] == R[u]) return;int mid = L[u] + R[u] >> 1;if (c <= mid) change(u << 1, a, b, c);else change(u << 1 | 1, a, b, c);
    }LL get_sum(int u, int l, int r, int pl, int pr, int add)
    {if (l >= pl && r <= pr) return tr[u].sum + (r - l + 1LL) * add;int mid = l + r >> 1;LL res = 0;add += tr[u].add;if (pl <= mid){if (tr[u].l) res += get_sum(tr[u].l, l, mid, pl, pr, add);else res += intersection(l, mid, pl, pr) * add;}if (pr > mid){if (tr[u].r) res += get_sum(tr[u].r, mid + 1, r, pl, pr, add);else res += intersection(mid + 1, r, pl, pr) * add;}return res;
    }int query(int u, int a, int b, int c)
    {if (L[u] == R[u]) return R[u];int mid = L[u] + R[u] >> 1;LL k = get_sum(T[u << 1 | 1], 1, n, a, b, 0);if (k >= c) return query(u << 1 | 1, a, b, c);return query(u << 1, a, b, c - k);
    }int main()
    {scanf("%d%d", &n, &m);for (int i = 0; i < m; i ++ ){scanf("%d%d%d%d", &q[i].op, &q[i].a, &q[i].b, &q[i].c);if (q[i].op == 1) nums.push_back(q[i].c);}sort(nums.begin(), nums.end());nums.erase(unique(nums.begin(), nums.end()), nums.end());build(1, 0, nums.size() - 1);for (int i = 0; i < m; i ++ ){int op = q[i].op, a = q[i].a, b = q[i].b, c = q[i].c;if (op == 1) change(1, a, b, get(c));else printf("%d\n", nums[query(1, a, b, c)]);}return 0;
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/853465.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jsp前端页面识别不了后端传过来的model-${user.id}

调试: controller 成功接收到参数。并且给model传入数据。界面也跳转了 jsp文件中使用 ${user.id} 获取数据 但是处理的依然是 ${user.id} 而不是传入来的数据。 原因: 默认创建的web,其配置文件 web.xml文件是使用 2.3版本 <!DOCTYPE web-app PUBLIC"-//Sun Micros…

基于ESP32的桌面小屏幕实战[4]:硬件设计之PCB Layout

1. PCB Layout 步骤生成PCB确定PCB layout规范绘制板框尺寸布局 布局规范:按电气性能合理分区,一般分为:数字电路区(即怕干扰、又产生干扰)、模拟电路区(怕干扰)、功率驱动区(干扰源); 完成同一功能的电路,应尽量靠近放置,并调整各元器件以保证连线最为简洁; 对于质…

【C#脚本】C#调用Python脚本的方式(一),以PaddleOCR-GUI为例

以下文章来源于mingupup的学习记录 ,作者DotNet学习交流 前言 每种语言都有每种语言的优势,Python由于其强大的生态,很多任务通过调用包就可以实现,那么学会从C#项目中调用Python脚本完成任务就很重要。C#调用Python代码有多种方式,如果Python那边内容比较多,可以考虑起一…

Derby 数据库介绍(1)--简介

Apache Derby 是 Apache DB 的一个子项目,是一个完全用 Java 实现的开源关系数据库,采用 Apache License 2.0 许可;本文主要介绍其基本概念及安装。 1、Derby 特点 Derby 体积小——基础引擎和嵌入式 JDBC 驱动程序约 3.5MB。Derby 基于 Java、JDBC 和 SQL 标准。Derby 提供…

参数占位符 #{xx} 和 ${xx} 的区别

#{xx} :带有#{}的SQL会采用SQL预编译技术,预编译后的SQL中 #{} 被替换为 “?”,这里的 “?”叫变量占位符,在实际执行SQL时会用“xx”的实际值替换变量占位符,效率更高,可以防止SQL注入SQL预编译:MySQL执行SQL有几个步骤,“查缓存->[语法分析->优化->编译-&…

三文带你轻松上手鸿蒙的 AI 语音 01-实时语音识别

三文带你轻松上手鸿蒙的 AI 语音 01-实时语音识别 前言 HarmonyOSNext中集成了强大的 AI 功能。Core Speech Kit(基础语音服务)是它提供的众多 AI 功能中的一种。 Core Speech Kit(基础语音服务)集成了语音类基础 AI 能力,包括文本转语音(TextToSpeech)及语音识别(Spee…

【原创】ARM64 实时linux操作系xenomai4(EVL)构建安装简述

本文简要记录在瑞芯微RK3588(ARM64)构建安装实时linux操作系统xenomai4的过程,以及实时性测试,希望对你有所帮助!目录0 环境说明1 内核构建2 库编译方式1 交叉编译方式2 本地编译3 测试单元测试hectic:EVL 上下文切换latmus:latency测试4 RK3588 xenomai4实时性能5 总结 本…

最新版chrome如何下载和安装?附安装包

前言 大家好,我是小徐啊。我们在Java开发应用的时候,经常是需要用到浏览器来帮助我们开发的。而浏览器中,谷歌浏览器chrome当属功能最强大的浏览器。今天小徐就来介绍下如何安装chrome。文末附获取方式。 如何安装chrome 首先,双击chrome的安装包,开始安装。然后,可以看到…

[笔记]均分纸牌问题

Index链形均分纸牌每次仅可交换\(1\)张 每次可交换多张环形均分纸牌每次仅可交换\(1\)张 每次可交换多张拓展性很强的贪心问题。或许能推广到树之类的结构上,或者拓展到方案计数问题之类,不过目前还没想好啦。 链形均分纸牌 每次仅可交换\(1\)张 最基础的例题是这样的:有\(n…

掌握PageRank算法核心!你离Google优化高手只差一步!

0 前言 98年前的搜索引擎体验不好:返回结果质量不高:搜索结果不考虑网页质量,而通过时间顺序检索易被钻空:搜索引擎基于检索词检索,页面中检索词出现的频次越高,匹配度越高,这样就会出现网页作弊的情况。有些网页为了增加搜索引擎的排名,故意增加某个检索词频率当时Goo…

ApacheDirectoryStudio如何安装和使用?附安装包

前言 大家好,我是小徐啊。ldap数据库是我们Java开发中,经常会用到的一种数据库。这种数据库是树形结构的,和平常的mysql等数据库还不太一样。但目前对应连接ldap数据库的连接工具比较少,且功能也不强大。今天,小徐就来介绍下一款比较好的连接ldap数据库的连接功能,那就是…

服务器 数据库被攻击如何处理

最近系统有点卡,查看了一下系统事件,发现有人攻击服务器数据库。 以下是我的解决方案 1、修改密码位复杂的密码 2、修改默认数据库默认端口目前已解决下面的腾讯的小哥给的建议,总体差不多一个意思 1、服务器设置大写、小写、特殊字符、数字组成的12-16位的复杂随机密码 ,…