4237: 稻草人

4237: 稻草人

Time Limit: 40 Sec   Memory Limit: 256 MB
Submit: 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

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

[ Submit][ Status][ Discuss]




此题展现了分治策略,,,感觉想不出来啊

对于所有点先按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;  
}  

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值