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