线段树套线段树,挺不错的一道数据结构题。
先读入所有询问并离散化,然后在外层建 权值线段树 ,
权值线段树的每个结点建一棵 维护区间和 的线段树。
直接建树空间 O(N2) 肯定会MLE,所以先建出权值线段树,再动态加点线段树维护区间和即可。
时间复杂度 O(logM∗logN∗M)
空间复杂度 O(M∗(logN)2)
学到了新姿势,重载括号运算符:
int& operator [](int id)
{
return *(__arr + id);
}
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <iostream>
#include <algorithm>
template<class Num>void read(Num &x)
{
char c; int flag = 1;
while((c = getchar()) < '0' || c > '9')
if(c == '-') flag *= -1;
x = c - '0';
while((c = getchar()) >= '0' && c <= '9')
x = (x<<3) + (x<<1) + (c-'0');
x *= flag;
return;
}
template<class Num>void write(Num x)
{
if(x < 0) putchar('-'), x = -x;
static char s[20];int sl = 0;
while(x) s[sl++] = x%10 + '0',x /= 10;
if(!sl) {putchar('0');return;}
while(sl) putchar(s[--sl]);
}
struct vetor
{
#define begin() (__arr + 1)
#define end() (__arr + __len + 1)
int *__arr, __len;
void set(int size)
{
__len = 0, __arr = (int*)malloc(sizeof(int)*size);
}
void push_back(int x)
{
__arr[++__len] = x;
}
int size()
{
return __len;
}
void unique()
{
std::sort(begin(),end());
__len = std::unique(begin(),end()) - begin();
}
int find(int x)
{
return std::lower_bound(begin(), end(), x)-begin()+1;
}
void erase()
{
__len = 0;
}
int& operator [](int id)
{
return *(__arr + id);
}
#undef begin
#undef end
}bowl;
#define REP(__i,__start,__end) for(int __i = (__start); __i <= (__end); __i++)
const int maxm = 5e4 + 50, maxn = 5e4 + 50;
const int logM = 16, logN = logM, size = logM*(logN<<1)*maxm + (maxm << 2);
struct type_op
{
int tp, a, b, c;
void init()
{
read(tp), read(a), read(b), read(c);
if(tp == 1) bowl.push_back(c);
}
}op[maxm];
int val[maxm << 2], lc[size], rc[size], cnt[size], addv[size];
int n, m, ind;
int pushdown(int si,int ll,int rr)
{
int mid = ll + rr >> 1;
if(!lc[si]) lc[si] = ++ind;
if(!rc[si]) rc[si] = ++ind;
cnt[lc[si]] += addv[si]*(mid - ll + 1);
cnt[rc[si]] += addv[si]*(rr - mid);
addv[lc[si]] += addv[si], addv[rc[si]] += addv[si], addv[si] = 0;
return mid;
}
void update(int si)
{
cnt[si] = cnt[lc[si]] + cnt[rc[si]];
}
void insert(int l,int r,int ll,int rr,int si)
{
if(l == ll && r == rr) cnt[si] += r - l + 1, addv[si] ++;
else
{
int mid = pushdown(si, ll, rr);
if(mid < l)
insert(l, r, mid + 1, rr, rc[si]);
else if(r <= mid)
insert(l, r, ll, mid, lc[si]);
else
{
insert(l, mid, ll, mid, lc[si]);
insert(mid + 1, r, mid + 1, rr, rc[si]);
}
update(si);
}
}
int query(int l,int r,int ll,int rr,int si)
{
if(l == ll && r == rr) return cnt[si];
else
{
int mid = pushdown(si, ll, rr);
if(mid < l)
return query(l, r, mid + 1, rr, rc[si]);
else if(r <= mid)
return query(l, r, ll, mid, lc[si]);
else
return query(l, mid, ll, mid, lc[si]) + query(mid + 1, r, mid + 1, rr, rc[si]);
update(si);
}
}
#define L(x) ((x)<<1)
#define R(x) ((x)<<1|1)
void build(int ll,int rr,int sv)
{
val[sv] = ++ind;
if(ll != rr)
{
int mid = ll + rr >> 1;
build(ll, mid, L(sv));
build(mid + 1, rr, R(sv));
}
}
void add(int l,int r,int v,int ll,int rr,int si)
{
insert(l, r, 1, n, val[si]);
if(ll != rr)
{
int mid = ll + rr >> 1;
if(v <= mid) add(l, r, v, ll, mid, L(si));
else add(l, r, v, mid + 1, rr, R(si));
}
}
int ask(int l,int r,int v,int ll,int rr,int si)
{
if(ll == rr) return ll;
int mid = ll + rr >> 1, rcnt;
if((rcnt = query(l, r, 1, n, val[R(si)])) >= v)
return ask(l, r, v, mid + 1, rr, R(si));
else
return ask(l, r, v - rcnt, ll, mid, L(si));
}
#undef L
#undef R
void init()
{
bowl.set(maxm), read(n), read(m);
REP(i, 1, m) op[i].init();
}
void prework()
{
bowl.unique();
REP(i, 1, m) if(op[i].tp == 1) op[i].c = bowl.find(op[i].c);
build(1, bowl.size(), 1);
}
void solve()
{
for(int i = 1; i <= m; i++)
{
if(op[i].tp == 1)
add(op[i].a, op[i].b, op[i].c, 1, bowl.size(), 1);
else
write(bowl[ask(op[i].a, op[i].b, op[i].c, 1, bowl.size(), 1)]), puts("");
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("3110.in","r",stdin);
freopen("3110.out","w",stdout);
#endif
init();
prework();
solve();
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}