BZOJ K大数查询(分治)(Zjoi2013)

时间:2021-03-25 20:42:14

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3110

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

输出每个询问的结果

 
题目大意:略。
思路:分治答案。答案范围[-n, n],从前往后扫描,若是插入操作且c>mid,则把线段树中区间[a, b]加一,并置为为类别1;否则置为类别0。若是询问操作,若目前线段树中区间[a, b]的和小于等于c,则置为类别1;否则置为类别0,并把c减去区间[a, b]的和。然后分治处理,其中类别0中,答案范围为[-n, mid];类别1中,答案范围为[mid + 1, n]。按类别排序后,两个区间之间互不影响。时间复杂度为O(nlognlogn)。
 
代码(4940MS):
 #include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL; const int MAXN = ;
const int MAXT = MAXN << ; int sum[MAXT];
int add[MAXT];
bool clr[MAXT]; #define ll (x << 1)
#define rr (ll | 1)
#define mid ((l + r) >> 1)
void initTree() {
sum[] = add[] = ;
clr[] = true;
} void pushdown(int x, int l, int r) {
if(clr[x]) {
clr[ll] = clr[rr] = true;
sum[ll] = sum[rr] = add[ll] = add[rr] = ;
clr[x] = false;
}
if(add[x]) {
sum[ll] += (mid - l + ) * add[x];
add[ll] += add[x];
sum[rr] += (r - mid) * add[x];
add[rr] += add[x];
add[x] = ;
}
} void maintain(int x) {
sum[x] = sum[ll] + sum[rr];
} void modify(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
add[x]++;
sum[x] += (r - l + );
} else {
pushdown(x, l, r);
if(a <= mid) modify(ll, l, mid, a, b);
if(mid < b) modify(rr, mid + , r, a, b);
maintain(x);
}
} int query(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
return sum[x];
} else {
pushdown(x, l, r);
int res = ;
if(a <= mid) res += query(ll, l, mid, a, b);
if(mid < b) res += query(rr, mid + , r, a, b);
return res;
}
}
#undef mid struct Node {
int op, id, a, b, c, v;
void read(int i) {
id = i;
scanf("%d%d%d%d", &op, &a, &b, &c);
}
bool operator < (const Node &rhs) const {
if(v != rhs.v) return v < rhs.v;
return id < rhs.id;
}
} p[MAXN];
int ans[MAXN];
int n, m; void work(int a, int b, int l, int r) {
if(l > r) return ;
if(a == b) {
for(int i = l; i <= r; ++i)
if(p[i].op == ) ans[p[i].id] = a;
return ;
}
initTree();
int mid = a + ((b - a) >> ), t = l - ;
for(int i = l; i <= r; ++i) {
if(p[i].op == ) {
if(p[i].c > mid) modify(, , n, p[i].a, p[i].b), p[i].v = ;
else p[i].v = ;
} else {
int s = query(, , n, p[i].a, p[i].b);
if(p[i].c <= s) p[i].v = ;
else p[i].v = , p[i].c -= s;
}
t += !p[i].v;
}
sort(p + l, p + r + );
work(a, mid, l, t);
work(mid + , b, t + , r);
} int main() {
scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++i) p[i].read(i);
memset(ans + , 0x80, m * sizeof(int));
work(-n, n, , m);
for(int i = ; i <= m; ++i)
if(ans[i] >= -n) printf("%d\n", ans[i]);
}