2527: [Poi2011]Meteors
Time Limit: 60 Sec Memory Limit: 128 MBSubmit: 2025 Solved: 731
[ Submit][ Status][ Discuss]
Description
这个星球经常会下陨石雨。BIU已经预测了接下来K场陨石雨的情况。 BIU的第i个成员国希望能够收集Pi单位的陨石样本。你的任务是判断对于每个国家,它需要在第几次陨石雨之后,才能收集足够的陨石。 输入: 第一行是两个数N,M。 第二行有M个数,第i个数Oi表示第i段轨道上有第Oi个国家的太空站。 第三行有N个数,第i个数Pi表示第i个国家希望收集的陨石数量。 第四行有一个数K,表示BIU预测了接下来的K场陨石雨。 接下来K行,每行有三个数Li,Ri,Ai,表示第K场陨石雨的发生地点在从Li顺时针到Ri的区间中(如果Li<=Ri,就是Li,Li+1,...,Ri,否则就是Ri,Ri+1,...,m-1,m,1,...,Li),向区间中的每个太空站提供Ai单位的陨石样本。 输出: N行。第i行的数Wi表示第i个国家在第Wi波陨石雨之后能够收集到足够的陨石样本。如果到第K波结束后仍然收集不到,输出NIE。 数据范围:数据范围: 1<=n,m,k<=3*10^5 1<=Pi<=10^9 1<=Ai<10^9
Input
Output
Sample Input
1 3 2 1 3
10 5 7
3
4 2 4
1 3 1
3 5 2
Sample Output
NIE
1
HINT
Source
从黄学长那里学了一下整体二分... 想了一下发现实际上是cdq分治的一种? 整体二分之所以为整体二分, 就是因为它二分的是所有询问. 具体可以看这道题.
这道题要求每个国家最早在第几次陨石雨的时候收集完所需的陨石样本. 显然这个具有二分性. 但是我们怎么快速的知道二分到某次陨石雨时某个国家有了多少陨石呢? 显然这个可以随便数据结构搞搞即可. 但是如果对每个国家都二分再用数据结构维护明显复杂度Booooom. 我们思考一下发现所有国家在二分到某次陨石雨时状态要么没收集完要么收集完了. 那么对于每次二分我们发现可以把国家分为两类, 一类没收集完, 一类收集完了, 再两边分别进入下一次的二分. 这样做有什么好处呢? 好处就在于我们所用的数据结构不只是针对一个国家, 而是可以针对一类国家了, 可以批量处理. 再细致想想, 每次二分分两类, 然后再分别进入下一次二分... 实际上就是cdq!! 这里相当于就是把答案当做时间来分治了嘛.
所以总的来说流程就是: 发现答案具有二分性, 离线, 将所有国家一起二分. 每次二分执行1 - mid(是1而不是l(L))的操作, 没有收集完的国家进入lf - mid的二分, 收集完了的进入mid + 1, rg的二分. 对于查询以及修改用树状数组维护即可.
可以多加一个全体加inf的操作来方便判断哪些国家肯定收集不完陨石.
#include<bits/stdc++.h>
using namespace std;
typedef long long lnt;
const int maxn = 3e5 + 5;
int n, m, Q, opt;
lnt c[maxn];
bool vis[maxn];
vector<int> a[maxn];
int l[maxn], r[maxn], val[maxn], p[maxn], tmp[maxn], ans[maxn], id[maxn];
inline const int read() {
register int x = 0;
register char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
inline void modify(int x, int val) {
for (int i = x; i <= m; i += i & -i) c[i] += val;
}
inline lnt query(int x) {
lnt tmp = 0;
for (int i = x; i; i -= i & -i) tmp += c[i];
return tmp;
}
inline void opera(int k, int f) {
if (l[k] <= r[k]) {
modify(l[k], f * val[k]);
modify(r[k] + 1, f * (-val[k]));
} else {
modify(1, f * val[k]);
modify(r[k] + 1, f * (-val[k]));
modify(l[k], f * val[k]);
}
}
void solve(int lf, int rg, int L, int R) {
register int i, j;
if (L == R) {
for (i = lf; i <= rg; ++ i) ans[id[i]] = L;
return;
}
int mid = (L + R) >> 1;
while (opt <= mid) opera(++ opt, 1);
while (opt > mid) opera(opt --, -1);
lnt sum = 0;
int nw, cnt = 0, siz;
for (i = lf; i <= rg; ++ i) {
sum = 0, nw = id[i], siz = a[nw].size();
for (j = 0; j < siz && sum < p[nw]; ++ j)
sum += query(a[nw][j]);
(p[nw] <= sum) ? vis[nw] = true, cnt ++ : vis[nw] = false;
}
int l1 = lf, l2 = lf + cnt;
for (i = lf; i <= rg; ++ i)
(vis[id[i]]) ? tmp[l1 ++] = id[i] : tmp[l2 ++] = id[i];
for (i = lf; i <= rg; ++ i) id[i] = tmp[i];
solve(lf, l1 - 1, L, mid), solve(l1, l2 - 1, mid + 1, R);
}
int main() {
n = read(), m = read();
register int i, x;
for (i = 1; i <= m; ++ i) x = read(), a[x].push_back(i);
for (i = 1; i <= n; ++ i) p[i] = read(), id[i] = i;
Q = read();
for (i = 1; i <= Q; ++ i) l[i] = read(), r[i] = read(), val[i] = read();
l[++ Q] = 1, r[Q] = m, val[Q] = 2100000000;
solve(1, n, 1, Q);
for (i = 1; i <= n; ++ i)
(ans[i] ^ Q) ? printf("%d\n", ans[i]) : puts("NIE");
return 0;
}