poj 2481 Cows(线段树)

本文介绍了解决POJ2481 Cows问题的方法,通过线段树来计算逆序数。文章详细讨论了在处理相同坐标区间时的特殊处理方法,并给出了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


poj 2481 Cows


这个题的线段树操作就相当于求个逆序数、但细节实现有些需要注意的

设每头牛的区间[x,y]

将所有区间按y降序排序,y相同时按x升序排序

这样一来y降序的情况下,后面某头牛的ans就是前面x比这头牛x小的个数,也就是求逆序数

但实际情况有些不一样,应为数据会出现x、y相等的情况

首先若x和y都相等,则复制前一头牛的ans

若只有y相等就要多注意下了:首先查询的时候还是查询[0,x]而不是[0,x-1],因为前面可能还有x和本x相等但y大于本y的,若查询[0,x-1]就把这一情况略过了。但查询[0,x]又会把前面和本x,y都相等的情况加进来,这里我的解决办法是直接爆了回搜减去x,y同时相等的个数,只能说幸好数据没卡这一点,庆幸没超时

剩下的直接查询[0,x]就是了


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lch p<<1
#define rch p<<1|1
#define mid (t[p].l+t[p].r)>>1;
#define MAXN 100005
struct node
{
	int l,r;
	int sum;
}t[MAXN<<2];
struct cows
{
	int x,y;
	int idx;
	int ans;
}c[MAXN];
bool cmp1(const cows &a,const cows &b)
{
	if(a.y==b.y) return a.x<b.x;
	else return a.y>b.y;
}
bool cmp2(const cows &a,const cows &b) {return a.idx<b.idx;}
void construct(int l,int r,int p)
{
	t[p].l=l,t[p].r=r,t[p].sum=0;
	if(l==r) return ;
	int m=mid;
	construct(l,m,lch);
	construct(m+1,r,rch);
}
void modify(int x,int p)
{
	if(t[p].l==t[p].r)
	{
		t[p].sum++;
		return ;
	}
	int m=mid;
	if(x<=m) modify(x,lch);
	else modify(x,rch);
	t[p].sum=t[lch].sum+t[rch].sum;
}
int query(int l,int r,int p)
{
	if(t[p].l==l&&t[p].r==r)
		return t[p].sum;
	int m=mid;
	if(r<=m) return query(l,r,lch);
	else if(l>m) return query(l,r,rch);
	else return query(l,m,lch)+query(m+1,r,rch);
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF&&n)
	{
		int maxx=0;
		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&c[i].x,&c[i].y);
			if(c[i].x>maxx) maxx=c[i].x;
			c[i].idx=i;
		}
		sort(c,c+n,cmp1);
		construct(0,maxx,1);
		for(int i=0;i<n;i++)
		{
			int tans=0;
			if(i>0&&c[i].y==c[i-1].y&&c[i].x==c[i-1].x)
				tans=c[i-1].ans;
			else if(i>0&&c[i].y==c[i-1].y)
			{
				int l=0,r=c[i].x;
				if(l<=r) tans=query(l,r,1);
				
				//幸好这一坨没超时
				for(int j=i-1;j>=0;j--)
					if(c[i].y==c[j].y&&c[i].x==c[j].x)
						tans--;
					else break;
			}
			else
			{
				int l=0,r=c[i].x;
				if(l<=r) tans=query(l,r,1);
			}
			c[i].ans=tans;
			modify(c[i].x,1);
		}
		sort(c,c+n,cmp2);
		printf("%d",c[0].ans);
		for(int i=1;i<n;i++) printf(" %d",c[i].ans);
		printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值