您的位置:首页 > 其它

[BZOJ3110][Zjoi2013]K大数查询

2016-02-03 12:39 525 查看

[Zjoi2013]K大数查询

Description

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c

如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

Input

第一行N,M

接下来M行,每行形如1 a b c或2 a b c

Output

输出每个询问的结果

Sample Input

2 5

1 1 2 1

1 1 2 2

2 1 1 2

2 1 1 1

2 1 2 3

Sample Output

1

2

1

HINT

【样例说明】

第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1

的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是

1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3

大的数是 1 。‍

N,M<=50000,N,M<=50000

a<=b<=N

1操作中abs(c)<=N

2操作中abs(c)<=Maxlongint

Solution

本来想树状数组套权值线段树的,发现空间炸裂,无奈只能权值套区间线段树。

外层是权值线段树,维护的是权值在[l,r]之间的数出现在了哪些区间,这个哪些区间就用挂在它下面的区间线段树来维护。

然后我们二分就可以做了。

Code

#include <bits/stdc++.h>
using namespace std;

#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define X first
#define Y second
#define PB push_back
#define MP make_pair
#define MS(_) memset(_, 0, sizeof(_))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef unsigned int ll;

const int N = 50000 + 10;
struct node{
ll sum, tag;
node *lc, *rc;
void modify(int l, int r, ll d) {sum += 1ll * (r-l+1) * d; tag += d;}
void sink(int l, int r);
void update() {sum = (lc ? lc->sum : 0) + (rc ? rc->sum : 0);}
}pool[N * 600], *tail = pool;
inline node *newnode() {return tail++;}
inline void node::sink(int l, int r){
if (!lc) lc = newnode(); lc->modify(l, l+r>>1, tag);
if (!rc) rc = newnode(); rc->modify((l+r>>1)+1, r, tag);
tag = 0;
}

struct NODE{
node *root;
NODE *LC, *RC;
}POOL[N << 2],    *ROOT, *TAIL = POOL;
inline NODE *NEWNODE() {return TAIL++;}

int n, m;

template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch))  {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}

inline void BUILD(NODE *(&RT), int L, int R){
RT = NEWNODE();  RT->root = newnode();
if (L == R) return;
int MID = L+R >> 1;
BUILD(RT->LC, L, MID); BUILD(RT->RC, MID+1, R);
}
inline void insert(node *rt, int l, int r, int ql, int qr){
rt->sink(l, r);
if (ql <= l && r <= qr) rt->modify(l, r, 1);
else{
int mid = l+r >> 1;
if (ql <= mid){
if (!rt->lc) rt->lc = newnode(); insert(rt->lc, l, mid, ql, qr);
}
if (qr > mid){
if (!rt->rc) rt->rc = newnode(); insert(rt->rc, mid+1, r, ql, qr);
}
rt->update();
}
}
inline void INSERT(NODE *RT, int L, int R, int ql, int qr, int pos){
insert(RT->root, 1, n, ql, qr);
if (L == R) return;
int MID = L+R >> 1;
if (pos <= MID) INSERT(RT->LC, L, MID, ql, qr, pos);
else INSERT(RT->RC, MID+1, R, ql, qr, pos);
}
inline ll query(node *rt, int l, int r, int ql, int qr){
rt->sink(l, r);
if (ql <= l && r <= qr) return rt->sum;
int mid = l+r >> 1; ll res = 0;
if (ql <= mid && rt->lc) res += query(rt->lc, l, mid, ql, qr);
if (qr > mid && rt->rc) res += query(rt->rc, mid+1, r, ql, qr);
return res;
}
inline void QUERY(NODE *RT, int L, int R, int ql, int qr, int rank){
if (L == R) {printf("%d\n", L); return;}
ll cnt = query(RT->RC->root, 1, n, ql, qr);
//debug("X = %d, ql = %d, qr = %d, cnt = %d\n", (L+R) >> 1, ql, qr, cnt);
int MID = L+R >> 1;
if (cnt < rank) QUERY(RT->LC, L, MID, ql, qr, rank-cnt);
else QUERY(RT->RC, MID+1, R, ql, qr, rank);
}

int main(){
read(n); read(m);
BUILD(ROOT, 1, n);
rep(i, 1, m){ int op, a, b, c;
read(op); read(a); read(b); read(c);
if (op == 1) INSERT(ROOT, 1, n, a, b, c);
else QUERY(ROOT, 1, n, a, b, c);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: