BZOJ 5052: 繁忙的财政官

对于每一个左端点,考虑其右边那些能更新答案的点
先考虑在其右边且值比当前大的,小的可以将值翻转后做一遍
即对左端点 \(i\),找到 \(j>i\) 满足 \(a_j>a_i\)
首先找到一个 \(j\),下次在 \(j\) 右边找到一个 \(k\) 满足 \(a_j > a_k > a_i\)
但是这样的点对还是有很多,考虑找下个 \(k\) 还有一些不优的答案,所以还要满足 \(a_j-a_k>a_k-a_i\)
\(a_k<\dfrac{a_i+a_j}{2}\)
这样找到的 \(a_k\) 每次至少减半,所以对于每一个左端点 \(i\) 要找的次数就是 \(\log v\),其中 \(v\) 表示值域
而找 \(j\)\(\log n\),所以复杂度为 \(O(n\log v \log n)\)
这样找出所有点对 \((i, j)\),扫描线扫右端点处理询问
对于每个点对是一个单点取min和区间求min
假设当前处理的右端点为 \(r\),每次查询的是 \([l,r]\),相当于 \([l, n]\) 一个后缀,所以可以将位置翻转后用树状数组维护

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)
#define ll long long
#define db double
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int ccnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 1e9 + 7;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
int gcd(int a, int b) { while (b) { a %= b; std::swap(a, b); } return a; }
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline char getc() {
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline int _() {
	int x = 0, f = 1; char ch = getc();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); }
	while (ch >= '0' && ch <= '9') { x = x * 10ll + ch - 48; ch = getc(); }
	return x * f;
}

const int N = 1e5 + 7;
const int INF = 0x3f3f3f3f;
int n, m, a[N], b[N], mn[N << 2], ans[N];
std::vector<std::pii> vec[N];
inline bool cmp(int x, int y) {
	return a[x] == a[y] ? x > y : a[x] > a[y];
}
void update(int p, int l, int r, int pos, int v) {
	mn[p] = std::min(mn[p], v);
	if (l == r) return;
	if (pos <= mid) update(lp, l, mid, pos, v);
	else update(rp, mid + 1, r, pos, v);
}
int query(int p, int l, int r, int pos, int v) {
	if (mn[p] > v) return 0;
	if (l == r) return l;
	if (pos <= mid) {
		int t = query(lp, l, mid, pos, v);
		if (t) return t;
	}
	return query(rp, mid + 1, r, pos, v);
}

struct QUERY {
	int l, r, id;
	bool operator < (const QUERY &p) const {
		return r < p.r;
	}
} Q[N];

void init() {
	std::sort(b + 1, b + 1 + n, cmp);
	memset(mn, 0x3f, sizeof(mn));
	rep (i, 1, n + 1) {
		int j = query(1, 1, n, b[i], INF - 1);
		while (j) {
			vec[j].pb(std::pii(b[i], a[j] - a[b[i]]));
			j = query(1, 1, n, b[i], (a[b[i]] + a[j] - 1) / 2);
		}
		update(1, 1, n, b[i], a[b[i]]);
	}
}
struct BIT {
	int tree[N];
	BIT() { memset(tree, 0x3f, sizeof(tree)); }
	inline int lowbit(int x) { return x & -x; }
	void add(int x, int v) {
		x = n - x + 1;
		for (int i = x; i <= n; i += lowbit(i))
			tree[i] = std::min(tree[i], v);
	}
	int query(int x) {
		x = n - x + 1;
		int ans = INF;
		for (int i = x; i; i -= lowbit(i))
			ans = std::min(ans, tree[i]);
		return ans;
	}
} bit;

int main() {
	n = _(), m = _();
	rep (i, 1, n + 1) a[i] = _(), b[i] = i;
	init();
	rep (i, 1, n + 1) a[i] = 1e9 - a[i] + 1;
	init();
	rep (i, 0, m) Q[i].l = _(), Q[i].r = _(), Q[i].id = i;
	std::sort(Q, Q + m);
	int cur = 1;
	rep (i, 0, m) {
		while (cur <= Q[i].r) {
			rep (j, 0, vec[cur].size()) bit.add(vec[cur][j].fi, vec[cur][j].se);
			cur++;
		}
		ans[Q[i].id] = bit.query(Q[i].l);
	}
	rep (i, 0, m) printf("%d\n", ans[i]);
	return 0;
}
posted @ 2020-02-25 11:45  Mrzdtz220  阅读(89)  评论(0编辑  收藏  举报