BZOJ2527 [Poi2011]Meteors 【整体二分 + 树状数组】
题目
Byteotian Interstellar Union有N个成员国。现在它发现了一颗新的星球,这颗星球的轨道被分为M份(第M份和第1份相邻),第i份上有第Ai个国家的太空站。
这个星球经常会下陨石雨。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。
输入样例
3 5
1 3 2 1 3
10 5 7
3
4 2 4
1 3 1
3 5 2
输出样例
3
NIE
1
提示
1<=n,m,k<=3*10^5
1<=Pi<=10^9
1<=Ai<10^9
题解
显然我们需要二分每个国家最早到达需求的时刻,但我们不可能每次都从头统计一遍
那就整体二分就搞定了√
具体地,每次对一个区间前半的操作进行操作,然后查看当前区间的询问是否满足,不满足就丢到左区间继续查询,否则就减去当前值后丢到右区间继续查询
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
#define lbt(x) (x & -x)
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 300005,maxm = 10000005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int n,m,K,q[maxn],p[maxn],t[maxn],ans[maxn];
LL S[maxn];
vector<int> at[maxn];
struct node{int l,r,v;}e[maxn];
void add(int u,LL v){while (u <= m) S[u] += v,u += lbt(u);}
LL query(int u){LL ans = 0; while (u) ans += S[u],u -= lbt(u); return ans;}
void solve(int l,int r,int L,int R){
if (L > R) return;
if (l == r){
for (int i = L; i <= R; i++) ans[q[i]] = l;
return;
}
int mid = l + r >> 1;
for (int i = l; i <= mid && i <= K; i++){
if (e[i].l <= e[i].r){
add(e[i].l,e[i].v);
add(e[i].r + 1,-e[i].v);
}
else {
add(1,e[i].v);
add(e[i].r + 1,-e[i].v);
add(e[i].l,e[i].v);
}
}
int li = L,ri = R;
LL tmp;
for (int i = L; i <= R; i++){
int u = q[i];
tmp = 0;
for (unsigned int j = 0; j < at[u].size(); j++)
tmp += query(at[u][j]);
if (tmp < p[u]) p[u] -= tmp,t[ri--] = u;
else t[li++] = u;
}
for (int i = L; i <= R; i++) q[i] = t[i];
for (int i = l; i <= mid && i <= K; i++){
if (e[i].l <= e[i].r){
add(e[i].l,-e[i].v);
add(e[i].r + 1,e[i].v);
}
else {
add(1,-e[i].v);
add(e[i].r + 1,e[i].v);
add(e[i].l,-e[i].v);
}
}
solve(l,mid,L,li - 1); solve(mid + 1,r,ri + 1,R);
}
int main(){
n = read(); m = read();
for (int i = 1; i <= m; i++){
int u = read();
at[u].push_back(i);
}
for (int i = 1; i <= n; i++) p[i] = read();
K = read();
for (int i = 1; i <= K; i++){
e[i].l = read();
e[i].r = read();
e[i].v = read();
}
for (int i = 1; i <= n; i++) q[i] = i;
solve(1,K + 1,1,n);
for (int i = 1; i <= n; i++){
if (ans[i] == K + 1) puts("NIE");
else printf("%d\n",ans[i]);
}
return 0;
}