题目链接: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 }