整体二分

整体二分

我们发现,题目满足二分性质, 但对于每一个询问二分又十分的慢,我们可以离线, 把答案一样的询问放在一起处理

  • 引入一道题

P3527 [POI2011]MET-Meteors

Solution

我们需要区间加和单点查询, 考虑使用树状数组

定义一个函数 $ f(l, r, L, R) $ 代表当前二分区间是 $ [l, r] $ , 答案在这个区间里的询问从 (L) 排到 (R)

设 $ mid = (l + r) >> 1 $ 我们把 $ [l, mid] $ 这段操作加进去

根据这次的操作,把询问分成两部分, 答案在 $ [l, mid] $ 内的和在 $ [mid + 1, r]$ 内的,递归直到 (l = r)

时间复杂度???

对于这道提来说, 类似线段树一样递归有 $ log m$ 层, 每层有 $ m $ 个操作,和 $ q $ 次询问

总体复杂度为 $ O((m + n) long^2 m) $

(code)

#include<iostream>
#include<cstdio>
#include<vector>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define rg register
char ss[1 << 17], *A = ss, *B = ss;
inline char gc(){ if(A == B) { B = (A = ss) + fread(ss, 1, 1 << 17, stdin); if(A ==B) return EOF; } return *A++; }
inline int read(){
	rg char ch = gc();
	rg int x = 0, f = 0;
	while(! isdigit(ch)) f |= (ch == '-'), ch = gc();
	while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
	return f ? -x : x;
}
const int N = 3e5 + 7;
long long g[N << 1];
int n, m, k;
inline void modify(int x, int d){
	for(int i = x; i; i ^= (i & -i)) g[i] += d;
}
inline long long ask(int x){
	long long res = 0;
	for(int i = x; i <= (m << 1); i += (i & -i)) res += g[i];
	return res;
}
inline void add(int l, int r, int d){
	modify(r, d);
	modify(l - 1, -d);
}
int o[N], p[N], id[N], ans[N];
int pre[N], pre_id[N];
vector<int> have[N];
struct node{
	int l, r, d;
	inline void init() { l = read(), r = read(), d = read(); }
	inline void modify() { :: add(l, r, d); }
	inline void in_modify() { :: add(l, r, -d); }
}q[N];
#define ll long long
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[id[i]] = l;
		return;
	}
	int mid = (l + r) >> 1;
	
	int tl = L - 1, tr = R + 1;
	for(int i = l; i <= mid; ++i) q[i].modify();
	for(int i = L; i <= R; ++i){
		ll tmp = 0;
		for(auto &x : have[id[i]]){
			tmp += ask(x) + ask(x + m);
			if(tmp >= p[i]) break;
		}
		if(tmp >= p[i]) pre[++tl] = p[i], pre_id[tl] = id[i];
		else pre[--tr] = p[i] - tmp, pre_id[tr] = id[i];
	}
	for(int i = l; i <= mid; ++i) q[i].in_modify();
	memcpy(p + L, pre + L, 4 * (tl - L + 1));
	memcpy(id + L, pre_id + L, 4 * (tl - L + 1));
	memcpy(p + tl + 1, pre + tl + 1, 4 * (R - tl));
	memcpy(id + tl + 1, pre_id + tl + 1, 4 * (R - tl));
	//for(int i = L; i <= tl; ++i) p[i] = pre[i], id[i] = pre_id[i];
	//for(int i = R; i >= tr; --i) p[i] = pre[i], id[i] = pre_id[i];
	solve(l, mid, L, tl); solve(mid + 1, r, tr, R);
}
signed main(){
	n = read(), m = read();
	for(int i = 1; i <= m; ++i) have[read()].push_back(i);
	for(int i = 1; i <= n; ++i) p[i] = read(), id[i] = i;
	k = read();
	for(int i = 1; i <= k; ++i) q[i].init();
	for(int i = 1; i <= k; ++i) if(q[i].r < q[i].l) q[i].r += m;
	q[k + 1].l = 1, q[k + 1].r = 1, q[k + 1].d = 0;
	solve(1, k + 1, 1, n);
	for(int i = 1; i <= n; ++i) (ans[i] == k + 1) ? puts("NIE") : printf("%d
", ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/XiaoVsun/p/13054254.html