BZOJ 4237: 稻草人

考虑cdq分治
\(y\) 坐标从小到大分为上下两个部分
现在统计下半部分对上半部分每一个点的贡献
那么下半部分能贡献的是一个斜率为负的类似于凸壳的形状
\(x\) 单调递增,\(y\) 单调递减,先按 \(x\) 排序,再单调栈维护 \(y\) 单调递减
但是这样有可能一些点被多算了,比如当前在上半部分的 \(a\) 位置,上半部分还存在一个 \(b\) 位置在 \(a\) 的左下角,那么在 \(b\) 左下角下半部分的就不能对 \(a\) 作贡献
那么在对上半部分维护一个 \(x\) 单调递增、\(y\) 单调递增的单调栈,那么下半部分能对当前点贡献的点即为 \(x\) 坐标大于在 \(a\) 之前所有点的 \(x\) 坐标

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<ll, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)
#define lowbit(i) ((i) & (-i))
#define ll long long
#define ull unsigned 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 = 2e5 + 7;
ll ans;
int n, st1[N], st2[N];
struct Node {
	int x, y;
} p[N];
bool cmpx(const Node &a, const Node &b) { return a.x < b.x; }
bool cmpy(const Node &a, const Node &b) { return a.y < b.y; }

void solve(int l, int r) {
	if (l >= r) return;
	solve(l, mid); solve(mid + 1, r);
	std::sort(p + l, p + mid + 1, cmpx);
	std::sort(p + mid + 1, p + r + 1, cmpx);
	int cur = l, top1 = 0, top2 = 0;
	rep (i, mid + 1, r + 1) {
		while (top1 && p[st1[top1]].y > p[i].y) top1--;
		st1[++top1] = i;
		while (cur <= mid && p[cur].x < p[i].x) {
			while (top2 && p[st2[top2]].y < p[cur].y) top2--;
			st2[++top2] = cur++;
		}
		int x = 1, y = top2, res = 0;
		while (x <= y) {
			int mi = x + y >> 1;
			if (p[st2[mi]].x < p[st1[top1 - 1]].x) x = mi + 1, res = mi;
			else y = mi - 1;
		}
		ans += top2 - res;
	}
}

int main() {
	n = _();
	rep (i, 1, n + 1) p[i].x = _(), p[i].y = _();
	p[0] = {-1, -1};
	std::sort(p + 1, p + 1 + n, cmpy);
	solve(1, n);
	printf("%lld\n", ans);
	return 0;
}
posted @ 2020-02-28 21:25  Mrzdtz220  阅读(89)  评论(0编辑  收藏  举报