4237: 稻草人
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 466 Solved: 194
[ Submit][ Status][ Discuss]
Description
JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典。
有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地。和启示中的一样,田地需要满足以下条件:
田地的形状是边平行于坐标轴的长方形;
左下角和右上角各有一个稻草人;
田地的内部(不包括边界)没有稻草人。
给出每个稻草人的坐标,请你求出有多少遵从启示的田地的个数
Input
第一行一个正整数N,代表稻草人的个数
接下来N行,第i行(1<=i<=N)包含2个由空格分隔的整数Xi和Yi,表示第i个稻草人的坐标
Output
输出一行一个正整数,代表遵从启示的田地的个数
Sample Input
4
0 0
2 2
3 4
4 3
0 0
2 2
3 4
4 3
Sample Output
3
HINT
所有满足要求的田地由下图所示:
1<=N<=2*10^5
0<=Xi<=10^9(1<=i<=N)
0<=Yi<=10^9(1<=i<=N)
Xi(1<=i<=N)互不相同。
Yi(1<=i<=N)互不相同。
Source
此题展现了分治策略,,,感觉想不出来啊
对于所有点先按x坐标从小到大排好
对于[L,R]的区间,矩形无非分为端点都在[L,mid]端点都在[mid+1,R]端点跨过中间
于是我们只需要处理端点跨过中间的,剩下的递归处理即可
在左半部分枚举左下角,暂时不考虑右上角具体取谁,而是考虑右上角能取的范围
事实上,找到当前点右上方中与当前点y坐标差值最小,记为(x',y'),右上角能取的纵坐标区间就为[y,y']
对于每个右上角,能取的左下角类似
对于左边的点按照y坐标降序重新排列
会限制当前点的那个点显然是在新序列中当前点位置左边,第一个x坐标大于当前点的点
维护一个单调栈O(n)统计
右上角类似
那么现在每个点都处理出一个可行区间,,
对于每个选作右上角的点,左下角的选取首先满足在当前可行区间内,
然后那个左下角的可行区间要包含当前点
统计的话用树状数组累加就行。。。
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 2E5 + 20;
typedef long long LL;
struct data{int x,y;} p[maxn];
struct d2{
int u,d; d2(){}
d2(int u,int d): u(u),d(d){}
bool operator < (const d2 &b) const {return u > b.u;}
}d[maxn];
int n,top,s[maxn],cy,ay[maxn],c[maxn];
LL ans;
bool cmpx(const data &a,const data &b) {return a.x < b.x;}
bool cmpy1(const data &a,const data &b) {return a.y > b.y;}
bool cmpy2(const data &a,const data &b) {return a.y < b.y;}
void Pre_Work(int L,int R)
{
int cur = 0; cy = 1;
for (int i = L; i <= R; i++) ay[++cur] = p[i].y;
sort(ay + 1,ay + cur + 1);
for (int i = 2; i <= cur; i++)
if (ay[i] != ay[i-1])
ay[++cy] = ay[i];
for (int i = 1; i <= cy; i++) c[i] = 0;
}
void Modify(int pos,int k)
{
pos = lower_bound(ay + 1,ay + cy + 1,pos) - ay;
for (int i = pos; i <= n; i += i&-i) c[i] += k;
}
int Sum(int L,int R)
{
L = lower_bound(ay + 1,ay + cy + 1,L) - ay;
R = lower_bound(ay + 1,ay + cy + 1,R) - ay;
int ret = 0;
for (int i = R; i > 0; i -= i&-i) ret += c[i];
for (int i = L - 1; i > 0; i -= i&-i) ret -= c[i];
return ret;
}
void Solve(int L,int R)
{
if (L == R) return;
int mid = (L + R) >> 1;
Solve(L,mid);
Solve(mid + 1,R);
Pre_Work(L,R);
sort(p + L,p + mid + 1,cmpy1);
s[top = 1] = L; int tot = 1;
d[1] = d2(ay[cy],p[L].y);
Modify(p[L].y,1);
for (int i = L + 1; i <= mid; i++) {
while (top && p[s[top]].x < p[i].x) --top;
if (top) d[++tot] = d2(p[s[top]].y,p[i].y);
else d[++tot] = d2(ay[cy],p[i].y);
Modify(p[i].y,1);
s[++top] = i;
}
sort(d + 1,d + tot + 1);
sort(p + mid + 1,p + R + 1,cmpy2);
s[top = 1] = mid + 1;
while (tot && d[tot].u < p[mid+1].y) Modify(d[tot--].d,-1);
ans += 1LL*Sum(ay[1],p[mid+1].y);
for (int i = mid + 2; i <= R; i++) {
while (top && p[s[top]].x > p[i].x) --top;
while (tot && d[tot].u < p[i].y) Modify(d[tot--].d,-1);
if (top) ans += 1LL*Sum(p[s[top]].y,p[i].y);
else ans += 1LL*Sum(ay[1],p[i].y);
s[++top] = i;
}
}
int getint()
{
char ch = getchar();
int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret*10 + ch - '0',ch = getchar();
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n;
for (int i = 1; i <= n; i++)
p[i].x = getint(),p[i].y = getint();
sort(p + 1,p + n + 1,cmpx);
Solve(1,n);
cout << ans;
return 0;
}