POJ-2481 Cows (线段树单点更新)

题目大意:给n个区间,对于任意一个区间,求出能完全包含它并且长度比它长的区间的个数。

题目分析:将一个区间视为二位坐标系中的一个点,左端点视作横坐标,右端点视作纵坐标。则题目变成了求每个点的左上方、正左方、正上方点的个数。将所有坐标先按纵坐标从大到小、再按横坐标从小到大排序。按顺序便利所有坐标,满足横坐标比当前坐标小或者满足横坐标不比当前横坐标大并且纵坐标比当前纵坐标大的点都是要找的点。用线段树维护即可,也可以用树状数组。

 

代码如下:

# include<iostream>
# include<cstdio>
# include<map>
# include<cstring>
# include<algorithm>
using namespace std;
# define LL long long

const int N=100000;
const int INF=10000000;

struct Coord
{
	int x,y,id;
	bool operator < (const Coord& a) const{
		if(y==a.y) return x<a.x;
		return y>a.y;
	}
};
Coord c[N+5];
int ans[N+5];
int tr[N*4+5];
int vis[N+5];

void update(int rt,int l,int r,int x)
{
	if(l==r){
		++tr[rt];
	}else{
		int mid=l+(r-l)/2;
		if(x<=mid)
			update(rt<<1,l,mid,x);
		else
			update(rt<<1|1,mid+1,r,x);
		tr[rt]=tr[rt<<1]+tr[rt<<1|1];
	}
}

int query(int rt,int l,int r,int L,int R)
{
	if(L>R) return 0;
	if(L<=l&&r<=R)
		return tr[rt];
	int res=0;
	int mid=l+(r-l)/2;
	if(L<=mid)
		res+=query(rt<<1,l,mid,L,R);
	if(R>mid)
		res+=query(rt<<1|1,mid+1,r,L,R);
	return res;
}

int main()
{
	int n;
	while(~scanf("%d",&n)&&n)
	{
		memset(tr,0,sizeof(tr));
		memset(ans,0,sizeof(ans));
		memset(vis,0,sizeof(vis));
		for(int i=0;i<n;++i){
			scanf("%d%d",&c[i].x,&c[i].y);
			c[i].id=i;
		}
		sort(c,c+n);
		vis[0]=0;
		for(int i=1;i<n;++i){
			if(c[i].x==c[i-1].x&&c[i].y==c[i-1].y) vis[i]=vis[i-1]+1;
			else vis[i]=0;
		}
		for(int i=0;i<n;++i){
			ans[c[i].id]+=query(1,0,N,0,c[i].x)-vis[i];
			update(1,0,N,c[i].x);
		}
		for(int i=0;i<n;++i)
			printf("%d%c",ans[i],(i==n-1)?'\n':' ');
	}
	return 0;
}

  

转载于:https://www.cnblogs.com/20143605--pcx/p/5461395.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值