bzoj 2527 [Poi2011]Meteors 整体二分+树状数组

题面

题目传送门

解法

不妨把每一个国家看成一组询问

那么,对于每一组询问显然满足单调性,可以二分答案

但是如果一个一个二分就比较慢,所以需要引入整体二分这个东西

整体二分就是二分当前答案,将可行的放在左边,不可行的放在右边,然后分别递归处理

本题用树状数组处理区间加减即可

时间复杂度:\(O(q\ log^2\ n)\)

代码

#include <bits/stdc++.h>
#define inf 1ll << 50
#define int long long
#define N 300010
using namespace std;
template <typename node> void read(node &x) {
	x = 0; int f = 1; char c = getchar();
	while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Node {
	int l, r, v;
} a[N];
int n, m, q, p[N], f[N], b[N], tx[N], ty[N], ans[N];
vector <int> e[N];
int lowbit(int x) {return x & -x;}
void modify(int x, int v) {
	for (int i = x; i <= m; i += lowbit(i))
		f[i] += v;
}
void Add(int l, int r, int v) {
	modify(l, v), modify(r + 1, -v);
	if (l > r) modify(m + 1, -v), modify(1, v);
}
int query(int x) {
	int ret = 0;
	for (int i = x; i; i -= lowbit(i))
		ret += f[i];
	return ret;
}
void solve(int l, int r, int L, int R) {
	if (L == R) {
		for (int i = l; i <= r; i++)
			ans[b[i]] = L;
		return;
	}
	int mid = (L + R) >> 1, l1 = 0, l2 = 0;
	for (int i = L; i <= mid; i++) Add(a[i].l, a[i].r, a[i].v);
	for (int i = l; i <= r; i++) {
		int x = b[i], sum = 0;
		for (int j = 0; j < e[x].size(); j++) {
			int k = e[x][j];
			sum += query(k);
			if (sum >= p[x]) break;
		}
		if (sum >= p[x]) tx[++l1] = x;
			else p[x] -= sum, ty[++l2] = x;
	}
	for (int i = l; i < l + l1; i++) b[i] = tx[i - l + 1];
	for (int i = l + l1; i <= r; i++) b[i] = ty[i - (l + l1) + 1];
	for (int i = L; i <= mid; i++) Add(a[i].l, a[i].r, -a[i].v);
	solve(l, l + l1 - 1, L, mid);
	solve(l + l1, r, mid + 1, R);
}
main() {
	read(n), read(m);
	for (int i = 1; i <= m; i++) {
		int x; read(x);
		e[x].push_back(i);
	}
	for (int i = 1; i <= n; i++) read(p[i]), b[i] = i;
	read(q);
	for (int i = 1; i <= q; i++)
		read(a[i].l), read(a[i].r), read(a[i].v);
	a[++q] = (Node) {1, m, inf};
	solve(1, n, 1, q);
	for (int i = 1; i <= n; i++)
		if (ans[i] == q) cout << "NIE\n";
			else cout << ans[i] << "\n";
	return 0;
}

posted @ 2018-08-14 22:21  谜のNOIP  阅读(92)  评论(0编辑  收藏  举报