【CDQ或并行二分】 SPOJ METEORS
题意:有m个空间站组成一个环形的轨道,每个空间站属于n个国家之一。一次流星雨可以给一段连续的空间站带来同样数量的陨石样本。给出每个国家需要的陨石数量和流星雨的出现情况,问每个国家最快在多少次流星雨前就能收集到需要数量的陨石
思路:分别二分算出答案即可
代码:
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int MAX_N = 300007; typedef pair<int,int> pii; typedef long long ll; template <class T> inline bool rd(T &ret) { char c; int sgn; if(c = getchar() , c == EOF) return false; while(c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return true; } struct Meteor { int l, r; ll v; } meteor[MAX_N]; int n, m, k; ll p[MAX_N]; int L[MAX_N], R[MAX_N], M[MAX_N]; pii unsolve[MAX_N]; bool suit[MAX_N]; vector<int> v[MAX_N]; struct Bit { ll bit[MAX_N]; void clear() { memset(bit, 0, sizeof bit); } void add(int i, ll v) { for (;i < MAX_N; i += i & -i) bit[i] += v; } ll query(int i) { ll re = 0; for (;i > 0; i -= i & -i) re += bit[i]; return re; } } B; void update(int id) { if (meteor[id].l <= meteor[id].r) { B.add(meteor[id].l, meteor[id].v); B.add(meteor[id].r + 1, -meteor[id].v); } else { B.add(meteor[id].l, meteor[id].v); B.add(m + 1, -meteor[id].v); B.add(1, meteor[id].v); B.add(meteor[id].r + 1, -meteor[id].v); } } void mid() { B.clear(); int now = 0; for (int i = 1; i <= n; ++i) if (L[i] != R[i]) unsolve[now++] = make_pair(M[i], i); int j = 1; sort(unsolve, unsolve + now); for (int i = 0; i < now; ++i) { while (j <= k && j <= unsolve[i].first) update(j++); int id = unsolve[i].second; ll now = 0;suit[id] = 0; for (int jj = 0; jj < v[id].size(); ++jj) { now += B.query(v[id][jj]); if (now >= p[id]) suit[id] = 1; } } } int main() { rd(n), rd(m); for (int i = 1; i <= m; ++i) { int x; rd(x); v[x].push_back(i); } for (int i = 1; i <= n; ++i) rd(p[i]); rd(k); for (int i = 1; i <= k; ++i) rd(meteor[i].l), rd(meteor[i].r), rd(meteor[i].v); for (int i = 1; i <= n; ++i) L[i] = 1, R[i] = k + 1; while (true) { for (int i = 1; i <= n; ++i) M[i] = L[i] + R[i] >> 1; mid(); bool ok = false; for (int i = 1; i <= n; ++i) if (L[i] != R[i]) { if (suit[i]) R[i] = M[i]; else L[i] = M[i] + 1; ok = true; } if (!ok) break; } for (int i = 1; i <= n; ++i) if (L[i] <= k) printf("%d\n", L[i]); else puts("NIE"); return 0; }