您的位置:首页 > 其它

[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

代码:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: