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

题目链接: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):
  1 #include <cstdio>

  2 #include <algorithm>

  3 #include <iostream>

  4 #include <cstring>

  5 using namespace std;

  6 typedef long long LL;

  7 

  8 const int MAXN = 50010;

  9 const int MAXT = MAXN << 2;

 10 

 11 int sum[MAXT];

 12 int add[MAXT];

 13 bool clr[MAXT];

 14 

 15 #define ll (x << 1)

 16 #define rr (ll | 1)

 17 #define mid ((l + r) >> 1)

 18 void initTree() {

 19     sum[1] = add[1] = 0;

 20     clr[1] = true;

 21 }

 22 

 23 void pushdown(int x, int l, int r) {

 24     if(clr[x]) {

 25         clr[ll] = clr[rr] = true;

 26         sum[ll] = sum[rr] = add[ll] = add[rr] = 0;

 27         clr[x] = false;

 28     }

 29     if(add[x]) {

 30         sum[ll] += (mid - l + 1) * add[x];

 31         add[ll] += add[x];

 32         sum[rr] += (r - mid) * add[x];

 33         add[rr] += add[x];

 34         add[x] = 0;

 35     }

 36 }

 37 

 38 void maintain(int x) {

 39     sum[x] = sum[ll] + sum[rr];

 40 }

 41 

 42 void modify(int x, int l, int r, int a, int b) {

 43     if(a <= l && r <= b) {

 44         add[x]++;

 45         sum[x] += (r - l + 1);

 46     } else {

 47         pushdown(x, l, r);

 48         if(a <= mid) modify(ll, l, mid, a, b);

 49         if(mid < b) modify(rr, mid + 1, r, a, b);

 50         maintain(x);

 51     }

 52 }

 53 

 54 int query(int x, int l, int r, int a, int b) {

 55     if(a <= l && r <= b) {

 56         return sum[x];

 57     } else {

 58         pushdown(x, l, r);

 59         int res = 0;

 60         if(a <= mid) res += query(ll, l, mid, a, b);

 61         if(mid < b) res += query(rr, mid + 1, r, a, b);

 62         return res;

 63     }

 64 }

 65 #undef mid

 66 

 67 struct Node {

 68     int op, id, a, b, c, v;

 69     void read(int i) {

 70         id = i;

 71         scanf("%d%d%d%d", &op, &a, &b, &c);

 72     }

 73     bool operator < (const Node &rhs) const {

 74         if(v != rhs.v) return v < rhs.v;

 75         return id < rhs.id;

 76     }

 77 } p[MAXN];

 78 int ans[MAXN];

 79 int n, m;

 80 

 81 void work(int a, int b, int l, int r) {

 82     if(l > r) return ;

 83     if(a == b) {

 84         for(int i = l; i <= r; ++i)

 85             if(p[i].op == 2) ans[p[i].id] = a;

 86         return ;

 87     }

 88     initTree();

 89     int mid = a + ((b - a) >> 1), t = l - 1;

 90     for(int i = l; i <= r; ++i) {

 91         if(p[i].op == 1) {

 92             if(p[i].c > mid) modify(1, 1, n, p[i].a, p[i].b), p[i].v = 1;

 93             else p[i].v = 0;

 94         } else {

 95             int s = query(1, 1, n, p[i].a, p[i].b);

 96             if(p[i].c <= s) p[i].v = 1;

 97             else p[i].v = 0, p[i].c -= s;

 98         }

 99         t += !p[i].v;

100     }

101     sort(p + l, p + r + 1);

102     work(a, mid, l, t);

103     work(mid + 1, b, t + 1, r);

104 }

105 

106 int main() {

107     scanf("%d%d", &n, &m);

108     for(int i = 1; i <= m; ++i) p[i].read(i);

109     memset(ans + 1, 0x80, m * sizeof(int));

110     work(-n, n, 1, m);

111     for(int i = 1; i <= m; ++i)

112         if(ans[i] >= -n) printf("%d\n", ans[i]);

113 }
View Code

 

你可能感兴趣的:(ZOJ)