权值线段树套线段树
之前没有做过权值线段树套外层树,也是第一次写动态开点的完整线段树
在push_down
的时候要动态开点。其实跟普通线段树是一样的。
写之前一定要先想清楚。外层的线段树是将值离散化后建的,外层的线段树可以用 o<<1
, o<<1|1
, 这样进行转移。内层的线段树需要动态开点,所以需要数组 lc[N]
, rc[N]
要计算开的空间大小。
/*
* @Author: zhl
* @Date: 2020-11-17 13:55:59
*/
#include<bits/stdc++.h>
#define mid (l + r >> 1)
#define lo (o << 1)
#define ro (o << 1 | 1)
using ll = long long;
using namespace std;
const int N = 5e4 + 10, P = N * 17 * 17, M = 4 * N;
int n, m;
int root[M], lc[P], rc[P], lz[P], tot;
ll sum[P];
void push_down(int u,int l,int r) {
if (!lc[u])lc[u] = ++tot;
lz[lc[u]] += lz[u];
if (!rc[u])rc[u] = ++tot;
lz[rc[u]] += lz[u];
sum[lc[u]] += (mid - l + 1) * lz[u];
sum[rc[u]] += (r - mid) * lz[u];
lz[u] = 0;
}
void updt(int& rt, int L,int R, int o = 1, int l = 1, int r = n) {
if (!rt) rt = ++tot;
if (L <= l and r <= R) {
lz[rt] ++;
//sum[rt] += R - L + 1;//我是傻逼草
sum[rt] += r - l + 1;
return;
}
if (lz[rt])push_down(rt, l , r);
if (L <= mid)updt(lc[rt], L, R, lo, l, mid);
if (R > mid)updt(rc[rt], L, R, ro, mid + 1, r);
sum[rt] = sum[lc[rt]] + sum[rc[rt]];
}
ll query(int rt, int L, int R, int o = 1, int l = 1, int r = n) {
if (!rt)return 0;
if (L <= l and r <= R) {
return sum[rt];
}
if (lz[rt])push_down(rt, l, r);
ll ans = 0;
if (L <= mid)ans += query(lc[rt], L, R, lo, l, mid);
if (R > mid) ans += query(rc[rt], L, R, ro, mid + 1, r);
return ans;
}
int cntID, id[N];
void add(int L,int R, int pos, int o = 1, int l = 1, int r = cntID) {
updt(root[o], L, R);
if (l == r)return;
if (pos <= mid)add(L, R, pos, lo, l, mid);
else add(L, R, pos, ro, mid + 1, r);
}
int get_kth(int L,int R,ll k,int o = 1, int l = 1, int r = cntID) {
if (l == r)return id[l];
ll num = query(root[ro], L, R);
if (num >= k) return get_kth(L, R, k, ro, mid + 1, r);
else return get_kth(L, R, k - num, lo, l, mid);
}
struct {
int op, a, b, c;
}q[N];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d%d", &q[i].op, &q[i].a, &q[i].b, &q[i].c);
if (q[i].op == 1) {
id[++cntID] = q[i].c;
}
}
sort(id + 1, id + 1 + cntID);
cntID = unique(id + 1, id + 1 + cntID) - id - 1;
for (int i = 1; i <= m; i++) {
if (q[i].op == 1)q[i].c = lower_bound(id + 1, id + 1 + cntID, q[i].c) - id;
}
for (int i = 1; i <= m; i++) {
if (q[i].op == 1) {
add(q[i].a, q[i].b, q[i].c);
}
else {
printf("%d
", get_kth(q[i].a, q[i].b, q[i].c));
}
}
}