[BZOJ3110][ZJOI2013]K大数查询(线段树套线段树)
2017-12-03 21:23
447 查看
有很多种解法。这里讲一种线段树套线段树的解法。这里外层的线段树是权值线段树,而内层的是位置线段树(保存对应权值范围的出现次数)。在空间问题上,使用动态开点。
对于修改,可以看作是对于权值c,位置区间[a,b]内的所有出现次数加1。也就是说,对于权值线段树从根节点到权值c代表的叶子节点的路径上的所有点所嵌套的位置线段树,都进行一次区间修改,即区间[a,b]加1,可以打标记。
对于询问,可以在权值线段树上二分,即如果右子节点(右子权值区间)所嵌套的线段树的[a,b]区间和小于等于c,就往右子树走,否则往左子树走,并且把c减去刚刚的询问结果。走到叶子节点时,答案就是该叶子节点对应的权值。
整体二分解法:http://blog.csdn.net/qq_18455665/article/details/50707462
代码:
对于修改,可以看作是对于权值c,位置区间[a,b]内的所有出现次数加1。也就是说,对于权值线段树从根节点到权值c代表的叶子节点的路径上的所有点所嵌套的位置线段树,都进行一次区间修改,即区间[a,b]加1,可以打标记。
对于询问,可以在权值线段树上二分,即如果右子节点(右子权值区间)所嵌套的线段树的[a,b]区间和小于等于c,就往右子树走,否则往左子树走,并且把c减去刚刚的询问结果。走到叶子节点时,答案就是该叶子节点对应的权值。
整体二分解法:http://blog.csdn.net/qq_18455665/article/details/50707462
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define p2 p << 1 #define p3 p << 1 | 1 using namespace std; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } typedef unsigned int ui; typedef long long ll; const int N = 4e5 + 5, M = 18e6 + 5; int n, m, rt , QAQ; struct cyx { int lc, rc; ui sum, add; void init() { lc = rc = sum = add = 0; } } T[M]; inline void modify(const int &l, const int &r, const int &s, const int &e, int &p) { if (!p) T[p = ++QAQ].init(); if (l == s && r == e) return (void) (T[p].add++); int mid = l + r >> 1; if (T[p].add) { if (!T[p].lc) T[T[p].lc = ++QAQ].init(); if (!T[p].rc) T[T[p].rc = ++QAQ].init(); T[T[p].lc].add += T[p].add; T[T[p].rc].add += T[p].add; T[p].add = 0; } if (e <= mid) modify(l, mid, s, e, T[p].lc); else if (s >= mid + 1) modify(mid + 1, r, s, e, T[p].rc); else modify(l, mid, s, mid, T[p].lc), modify(mid + 1, r, mid + 1, e, T[p].rc); T[p].sum = T[T[p].lc].sum + T[T[p].rc].sum + T[T[p].lc].add * (mid - l + 1) + T[T[p].rc].add * (r - mid); } inline void change(const int &l, const int &r, const int &s, const int &e, const int &v, const int &p) { modify(1, n, s, e, rt[p]); if (l == r) return; int mid = l + r >> 1; if (v <= mid) change(l, mid, s, e, v, p2); else change(mid + 1, r, s, e, v, p3); } inline ui query(const int &l, const int &r, const int &s, const int &e, int &p) { if (!p) T[p = ++QAQ].init(); if (l == s && r == e) return T[p].sum + T[p].add * (r - l + 1); int mid = l + r >> 1; if (T[p].add) { if (!T[p].lc) T[T[p].lc = ++QAQ].init(); if (!T[p].rc) T[T[p].rc = ++QAQ].init(); T[T[p].lc].add += T[p].add; T[T[p].rc].add += T[p].add; T[p].add = 0; } ui res; if (e <= mid) res = query(l, mid, s, e, T[p].lc); else if (s >= mid + 1) res = query(mid + 1, r, s, e, T[p].rc); else res = query(l, mid, s, mid, T[p].lc) + query(mid + 1, r, mid + 1, e, T[p].rc); T[p].sum = T[T[p].lc].sum + T[T[p].rc].sum + T[T[p].lc].add * (mid - l + 1) + T[T[p].rc].add * (r - mid); return res; } inline int ask(const int &l, const int &r, const int &s, const int &e, const ll &c, const int &p) { if (l == r) return l; int mid = l + r >> 1; ui tmp = query(1, n, s, e, rt[p3]); if (c <= tmp) return ask(mid + 1, r, s, e, c, p3); else return ask(l, mid, s, e, c - tmp, p2); } int main() { int a, b, c, op; n = read(); m = read(); ll d; while (m--) { op = read(); a = read(); b = read(); op == 1 ? c = read() : scanf("%lld", &d); if (op == 1) change(1, n, a, b, c, 1); else printf("%d\n", ask(1, n, a, b, d, 1)); } return 0; }
相关文章推荐
- bzoj3110 [Zjoi2013]K大数查询(整体二分+线段树)
- bzoj 3110: [Zjoi2013]K大数查询 线段树套线段树
- 【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树
- 【BZOJ3110】【Zjoi2013】K大数查询 树套树 权值线段树套区间线段树
- BZOJ 3110 ZJOI 2013 K大值查询 线段树套线段树
- bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
- 【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树
- BZOJ 3110 [Zjoi2013]K大数查询 (整体二分 + 树状数组或线段树处理区间合值)
- BZOJ 3110: [Zjoi2013]K大数查询|线段树套线段树
- 【bzoj3110】【ZJOI2013】【K大数查询】【权值线段树套位置线段树】
- 【线段树套线段树】[ZJOI 2013] bzoj3110 K大数查询
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
- 【BZOJ3110】K大数查询(ZJOI2013)-整体二分+线段树
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
- bzoj3110[Zjoi2013]K大数查询 主席树套线段树
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
- [BZOJ3110][Zjoi2013]K大数查询(主席树套线段树||整体二分 )
- [BZOJ]3110: [Zjoi2013]K大数查询 整体二分+线段树
- 【BZOJ3110】【ZJOI2013】K大数查询