可持久化线段树
来源:互联网 发布:语音对话机器人app源码 编辑:程序博客网 时间:2024/06/05 06:20
可持久化线段树
简介
可持久化数据结构又称函数式数据结构,其思路来自于函数式编程。在函数式编程中,变量的值是不允许改变的,因而每一次插入元素都必须创建一个新的版本。
设想一棵二叉树:
[1] [2] [3] [4] [5] [6]
现在为了插入一个新节点,我们必须新建一棵树
(1) (2) (3) (4) (5) (6) (7)
不难发现,很多元素被重复使用了。如果将重复的元素合并,就得到这样一棵树:
[1] ---> (1) [2] [3] [2] (3) [4] [5] [6] [6] (7)
新建的元素其实只有
应用
可持久化线段树是解决区间问题的锐利武器。考虑第
例如vijos1459
车展一题。用反证法不难证明题目中要求的即是
其中,
由于涉及了区间中位数,可以考虑使用树套树实现。但树套树代码复杂度较高且不宜于调试,可以考虑用可持久化线段树代替。
将输入的 sum
和num_sum
,第一个为区间内元素的和,第二个为区间内元素出现的次数。利用
Code
// 可持久化线段树// 维护两个值#include <bits/stdc++.h>using namespace std;#define maxn 1005struct node { int l, r, lc, rc; long long sum; int num_sum; node(){l = r = lc = rc = sum = num_sum = 0; }}tree[15*maxn];int root[200005], top = 0;int n, m;inline long long read(){ long long a = 0; int c; do c = getchar(); while(!isdigit(c)); while (isdigit(c)) { a = a*10 + c - '0'; c = getchar(); } return a;}int sorted[1005]; // 离散化int dat[1005]; // 原始数据inline void update(int i) { tree[i].sum = tree[tree[i].lc].sum + tree[tree[i].rc].sum; tree[i].num_sum = tree[tree[i].lc].num_sum + tree[tree[i].rc].num_sum;}inline int new_node(int l, int r) { tree[++top].l = l; tree[top].r = r; return top;}void build(int &nd, int l, int r) { if (l > r) return; if (l == r) {nd = new_node(l, r);return;} int mid = (l+r)>>1; nd = new_node(l, r); build(tree[nd].lc, l, mid); build(tree[nd].rc, mid+1, r);}void insert(int pre, int &now, int k, long long dat) { if (tree[pre].l == tree[pre].r) { now = new_node(k, k); tree[now].sum = dat; tree[now].num_sum = 1; } else { now = new_node(tree[pre].l, tree[pre].r); tree[now] = tree[pre]; if (k <= tree[tree[pre].lc].r) insert(tree[pre].lc, tree[now].lc, k, dat); else insert(tree[pre].rc, tree[now].rc, k, dat); update(now); }}// 查找区间和(sum)long long get_sum(int pre, int now, int l, int r){ if (l > r || !pre || !now) return 0; if (l == tree[pre].l && r == tree[now].r) return tree[now].sum - tree[pre].sum; return get_sum(tree[pre].lc, tree[now].lc, l, min(r, tree[tree[pre].lc].r)) + get_sum(tree[pre].rc, tree[now].rc, max(tree[tree[pre].rc].l, l), r);}// 区间内数字个数的和int get_num_sum(int pre, int now, int l, int r){ if (l > r || !pre || !now) return 0; if (l == tree[pre].l && r == tree[now].r) return tree[now].num_sum - tree[pre].num_sum; return get_num_sum(tree[pre].lc, tree[now].lc, l, min(r, tree[tree[pre].lc].r)) + get_num_sum(tree[pre].rc, tree[now].rc, max(tree[tree[pre].rc].l, l), r);}int find_mid(int pre, int now, int k) // 查找中位数(第k个数)的位置{ if (tree[now].l == tree[now].r) return tree[now].l; if (tree[tree[now].lc].num_sum - tree[tree[pre].lc].num_sum >= k) return find_mid(tree[pre].lc, tree[now].lc, k); else return find_mid(tree[pre].rc, tree[now].rc, k-(tree[tree[now].lc].num_sum - tree[tree[pre].lc].num_sum));}// 查询区间long long query(int l, int r) { int pos = find_mid(root[l-1], root[r], ((l+r)>>1)-l+1); long long lft = get_sum(root[l-1], root[r], 1, pos);int ln = get_num_sum(root[l-1], root[r], 1, pos); long long rgt = get_sum(root[l-1], root[r], pos+1, n);int rn = get_num_sum(root[l-1], root[r], pos+1, n); return rgt - rn*sorted[pos] + ln*sorted[pos] - lft;}void dfs(int rt, int tab = 0) { if (rt) { for (size_t i = 0; i < tab; i++) putchar(' '); cout << tree[rt].l << "->" << tree[rt].r << " " << tree[rt].sum << " " << tree[rt].num_sum << endl; dfs(tree[rt].lc, tab+2); dfs(tree[rt].rc, tab+2); }}int main(){ n = read(); m = read(); build(root[0], 1, n); long long a, l, r; for (size_t i = 1; i <= n; i++) sorted[i] = dat[i] = read(); sort(sorted+1, sorted+n+1); for (size_t i = 1; i <= n; i++) { insert(root[i-1], root[i], lower_bound(sorted+1, sorted+n+1, dat[i])-sorted, dat[i]); } long long ans = 0; for (size_t i = 1; i <= m; i++) { l = read(); r = read(); ans += query(l, r); } cout << ans << endl; return 0;}
0 0
- 可持久化线段树
- 可持久化线段树
- 可持久化线段树
- 可持久化线段树
- 可持久化线段树
- 可持久化线段树
- 可持久化线段树
- hdu 4348 可持久化线段树
- [Spoj]MKTHNUM 可持久化线段树
- HDU4866 Shooting (可持久化线段树)
- 可持久化线段树 HDU4866 Shooting
- 【Codechef ForbidenSum】可持久化线段树
- 可持久化线段树(poj2104/hdu4866)
- 可持久化线段树HDU2665、bzoj3207
- 可持久化线段树笔记
- BZOJ2223(可持久化线段树)
- 【模板】可持久化线段树
- *hdu 2665 (可持久化线段树)
- Java集群优化——dubbo+zookeeper构建高可用分布式集群
- Linux中设置服务自启动的三种方式
- 初学模糊的css盒子模型和位置问题
- Redis专题 -- 初识redis
- scrollView + viewPager + listView等复杂界面需求的实现
- 可持久化线段树
- Glide加载https图片
- Connection 元数据的使用例子
- VerticalSeekbar自适应屏幕旋转响应
- cogs396 [网络流24题]魔术球问题简化版
- Python爬虫包 BeautifulSoup 学习(四) bs基本对象与函数
- 12306.cn网站挂了”好文章收藏,引发的技术架构问题讨论。
- 时间戳
- javaScript 高阶函数 map/reduce/filter