线段树分裂
P5494 【模板】线段树分裂
题目链接P5494 【模板】线段树分裂 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
/*
给出一个可重集 aa(编号为 11),它支持以下操作:
0 p x y:将可重集 pp 中大于等于 xx 且小于等于 yy 的值放入一个新的可重集中
(新可重集编号为从 2 开始的正整数,是上一次产生的新可重集的编号+1)。
1 p t:将可重集 tt 中的数放入可重集 pp,且清空可重集 tt(数据保证在此后的操作中不会出现可重集 tt)。
2 p x q:在 pp 这个可重集中加入 xx 个数字 qq。
3 p x y:查询可重集 pp 中大于等于 xx 且小于等于 yy 的值的个数。
4 p k:查询在 pp 这个可重集中第 kk 小的数,不存在时输出 -1。
*/
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
const int maxn = 200010;
struct sgt_tree//线段树的分裂与合并
{
#define ls (son[p][0])
#define rs (son[p][1])
int son[maxn << 5][2];//记录左右儿子编号
ll val[maxn << 5];//权值
int bac[maxn << 5], tot, cnt;//垃圾回收
int addnode() { return cnt ? bac[cnt--] : ++tot; }
void del(int p) {
bac[++cnt] = p; son[p][0] = son[p][1] = val[p] = 0;
}
void modify(int& p, int l, int r, int pos, int v) {
//单点修改
if (!p)p = addnode();
val[p] += v;
if (l == r)return;
int mid = (l + r) >> 1;
if (pos <= mid)modify(ls, l, mid, pos, v);
else modify(rs, mid + 1, r, pos, v);
}
ll query(int p, int l, int r, int ql, int qr) {
//区间和查询
if (l > qr || r < ql)return 0;
if (ql <= l && r <= qr)return val[p];
int mid = (l + r) >> 1;
return query(ls, l, mid, ql, qr) + query(rs, mid + 1, r, ql, qr);
}
int kth(int p, int l, int r, int k) {
//第k小查询
if (l == r)return l;
int mid = (l + r) >> 1;
if (val[ls] >= k)return kth(ls, l, mid, k);
else return kth(rs, mid + 1, r, k - val[ls]);
}
int merge(int x, int y)
{
//线段树的合并
if (!x || !y)return x + y;
val[x] += val[y];
son[x][0] = merge(son[x][0], son[y][0]);
son[x][1] = merge(son[x][1], son[y][1]);
del(y);
return x;
}
void split(int x, int& y, ll k)
{
//线段树分裂前k个数出来
if (x == 0)return;
y = addnode();
ll v = val[son[x][0]];
if (k > v)split(son[x][1], son[y][1], k - v);
else swap(son[x][1], son[y][1]);
if (k < v)split(son[x][0], son[y][0], k);
val[y] = val[x] - k;
val[x] = k;
return;
}
#undef ls
#undef rs
}sgt;
int rt[maxn], seq = 1;
int n, m;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
int x; scanf("%d", &x);
sgt.modify(rt[1], 1, n, i, x);
}
for (int i = 1; i <= m; i++)
{
int op, x, y, z;
scanf("%d", &op);
if (op == 0)
{
scanf("%d%d%d", &x, &y, &z);
ll k1 = sgt.query(rt[x], 1, n, 1, z), k2 = sgt.query(rt[x], 1, n, y, z);
int tmp = 0;
sgt.split(rt[x], rt[++seq], k1 - k2);
sgt.split(rt[seq], tmp, k2);
rt[x] = sgt.merge(rt[x], tmp);
}
else if (op == 1)
{
scanf("%d%d", &x, &y);
rt[x] = sgt.merge(rt[x], rt[y]);
}
else if (op == 2)
{
scanf("%d%d%d", &x, &y, &z);
sgt.modify(rt[x], 1, n, z, y);
}
else if (op == 3)
{
scanf("%d%d%d", &x, &y, &z);
printf("%lld\n", sgt.query(rt[x], 1, n, y, z));
}
else if (op == 4)
{
scanf("%d%d", &x, &y);
if (sgt.val[rt[x]] < y)puts("-1");
else printf("%d\n", sgt.kth(rt[x], 1, n, y));
}
}
return 0;
}

浙公网安备 33010602011771号