模板链接
最早从zx神仙口中得知这个玩意,但是一直没学,现在学一下再说,发现不是什么神仙东西,说实话有点小失落.按照区间分裂可以在
O
(
l
o
g
n
)
O(logn)
O(logn)内完成,不过,合并操作需要枚举线段树的每个点进行合并,效率不是太高,数据量1e3差不多就是极限了.且应用面不是很广.
洛谷所给的模板是多个权值线段树的维护操作.
下面是模板代码:
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
const int N = 2e6+5;
int n, m, tot, cnt, seq = 1;
int bac[N<<5], rt[N];
struct Node
{
int l, r;
ll val;
}tr[N<<5];
inline int newnod() {return (cnt?bac[cnt--]:++tot);}
inline void del(int p) {bac[++cnt] = p; tr[p].l = tr[p].r = tr[p].val = 0;}
void change(int &p, int l, int r, int pos, int v)
{
if (!p) {p=newnod();}
tr[p].val += v;
if (l == r) return;
int mid = (l + r) >> 1;
if (pos <= mid) change(tr[p].l, l, mid, pos, v);
else change(tr[p].r, mid+1, r, pos, v);
}
ll ask(int p, int l, int r, int xl, int xr)
{
if (xr < l || r < xl) return 0;
if (xl <= l && r <= xr) return tr[p].val;
int mid = (l + r) >> 1;
return ask(tr[p].l, l, mid, xl, xr) + ask(tr[p].r, mid+1, r, xl, xr);
}
int grank(int p, int l, int r, int k)
{
if (l == r) return l;
int mid = (l + r) >> 1;
if (tr[tr[p].l].val >= k) return grank(tr[p].l, l, mid, k);
else return grank(tr[p].r, mid+1, r, k - tr[tr[p].l].val);
}
int merge(int x, int y)
{
if (!x || !y) return x + y;
tr[x].val += tr[y].val;
tr[x].l = merge(tr[x].l, tr[y].l);
tr[x].r = merge(tr[x].r, tr[y].r);
del(y);
return x;
}
void split(int x, int &y, ll k)
{
y = newnod();
ll v = tr[tr[x].l].val;
if (k > v) split(tr[x].r, tr[y].r, k-v);
else swap(tr[x].r, tr[y].r);
if (k < v) split(tr[x].l, tr[y].l, k);
tr[y].val = tr[x].val - k;
tr[x].val = k;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
int x;
scanf("%d", &x), change(rt[1], 1, n, i, x);
}
while(m--)
{
int op; scanf("%d", &op);
int x, y, z;
if (op == 0)
{
scanf("%d%d%d", &x, &y, &z);
ll k1 = ask(rt[x], 1, n, 1, z), k2 = ask(rt[x], 1, n, y, z);
int te = 0;
split(rt[x], rt[++seq], k1-k2);
split(rt[seq], te, k2);
rt[x] = merge(rt[x], te);
}
else if (op == 1)
{
scanf("%d%d", &x, &y);
rt[x] = merge(rt[x], rt[y]);
}
else if (op == 2)
{
scanf("%d%d%d", &x, &y, &z);
change(rt[x], 1, n, z, y);
}
else if (op == 3)
{
scanf("%d%d%d", &x, &y, &z);
printf("%lld\n", ask(rt[x], 1, n, y, z));
}
else if (op == 4)
{
scanf("%d%d", &x, &y);
if (tr[rt[x]].val < y) puts("-1");
else printf("%d\n", grank(rt[x], 1, n, y));
}
}
return 0;
}