Problem
【POI2011】Meteors
TimeLimit:60Sec
MemoryLimit:128MB
Description
ByteotianInterstellarUnion有N个成员国。
现在它发现了一颗新的星球,这颗星球的轨道被分为M份(第M份和第1份相邻),第i份上有第Ai个国家的太空站。
这个星球经常会下陨石雨。BIU已经预测了接下来K场陨石雨的情况。BIU的第i个成员国希望能够收集Pi单位的陨石样本。
你的任务是判断对于每个国家,它需要在第几次陨石雨之后,才能收集足够的陨石。
第一行输入两个数N,M。
第二行有M个数,第i个数Oi表示第i段轨道上有第Oi个国家的太空站。
第三行有N个数,第i个数Pi表示第i个国家希望收集的陨石数量。
第四行有一个数K,表示预测了接下来的K场陨石雨。
接下来K行,每行有三个数Li,Ri,Ai,表示第K场陨石雨的发生地点在从Li顺时针到Ri的区间中(如果Li≤Ri,就是Li,Li+1,⋯,Ri,否则就是Ri,Ri+1,⋯,m−1,m,1,⋯,Li),向区间中的每个太空站提供Ai单位的陨石样本。
Output
输出共N行。
第i行的数Wi表示第i个国家在第Wi波陨石雨之后能够收集到足够的陨石样本。
如果到第K波结束后仍然收集不到,输出NIE
。
1 2 3 4 5 6 7
| 3 5 1 3 2 1 3 10 5 7 3 4 2 4 1 3 1 3 5 2
|
Sample Output
HINT
1≤n,m,k≤3×105,1≤Pi≤109,1≤Ai<109。
Source
鸣谢Object022
标签:整体二分
Solution
整体二分模板题。
将所有询问离线下来一起做二分答案。对于二分中点tans,考虑每个国家是否能在前tans波流星雨之内达到收集要求。对每个国家用树状数组统计出会有多少陨石落到它的所有卫星上,即可判断每个询问的答案在[s,tans]中还是[tans+1,t]中。
注意每次判的时候不要将1∼tans区间内的所有流星雨都加入树状数组修改,这样复杂度是伪的。应当对于每个答案区间在[tans+1,t]中的询问累加前面的陨石总数,即累加前面区间对后面的贡献。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include <bits/stdc++.h> #define MAX_N 20000 #define INF 0x3f3f3f3f #define mid ((s+t)>>1) using namespace std; template <class T> inline void read(T &x) { x = 0; int c = getchar(), f = 1; for (; !isdigit(c); c = getchar()) if (c == 45) f = -1; for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0'); } int N, M, Q, cnt, val[MAX_N+5], ans[MAX_N+5]; struct node {int id, tp, a, b, k, s;} p[MAX_N+5], q[MAX_N+5]; int num[MAX_N+5], tr[MAX_N+5]; bool mrk[MAX_N+5]; void inc(int p) {for (; p <= N; p += (p&-p)) tr[p]++;} void dec(int p) {for (; p <= N; p += (p&-p)) tr[p]--;} int sum(int p) {int ret = 0; for (; p; p -= (p&-p)) ret += tr[p]; return ret;} void bi_solve(int l, int r, int s, int t) { if (l > r) return; if (s == t) { for (int i = l; i <= r; i++) if (p[i].tp == 3) ans[p[i].id] = s; return; } for (int i = l; i <= r; i++) if (p[i].tp == 1 && p[i].b <= mid) inc(p[i].a); else if (p[i].tp == 2 && p[i].b <= mid) dec(p[i].a); else if (p[i].tp == 3) num[i] = sum(p[i].b)-sum(p[i].a-1); for (int i = l; i <= r; i++) if (p[i].tp == 1 && p[i].b <= mid) dec(p[i].a); else if (p[i].tp == 2 && p[i].b <= mid) inc(p[i].a); int lsz = 0; for (int i = l; i <= r; i++) if (p[i].tp == 3) { if (p[i].k <= p[i].s+num[i]) lsz++, mrk[i] = false; else p[i].s += num[i], mrk[i] = true; } else lsz += (p[i].b <= mid), mrk[i] = (p[i].b > mid); for (int i = l, p1 = l, p2 = l+lsz; i <= r; i++) if (!mrk[i]) q[p1++] = p[i]; else q[p2++] = p[i]; for (int i = l; i <= r; i++) p[i] = q[i]; bi_solve(l, l+lsz-1, s, mid), bi_solve(l+lsz, r, mid+1, t); } int main() { read(N), read(M); for (int i = 1; i <= N; i++) read(val[i]), p[++cnt] = (node){0, 1, i, val[i], 0, 0}; for (int i = 1, a, b, k; i <= M; i++) { char opt[2]; scanf("%s", opt); if (opt[0] == 'C') read(a), read(b), p[++cnt] = (node){0, 2, a, val[a], 0, 0}, p[++cnt] = (node){0, 1, a, (val[a] = b), 0, 0}; else read(a), read(b), read(k), p[++cnt] = (node){++Q, 3, a, b, k, 0}; } bi_solve(1, cnt, 0, INF); for (int i = 1; i <= Q; i++) printf("%d\n", ans[i]); return 0; }
|