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;
}

posted @ 2018-04-09 19:45  Mychael  阅读(176)  评论(0编辑  收藏  举报