暑假-树状数组-D - Cows

题意:有n头牛,每头牛都是自己的领域 [Si, Ei], 如果Si <= Sj 并且 Ej <= Ei 并且 Ei - Si > Ej - Sj,就认为第i 头牛比第j头牛强壮.问对于每头牛,有多少头牛比它强壮。

思路:相当于求对于第i头牛的区间的真子集个数,但是对于一维区间[Si,Ei]我们可以用二维的点(x,y)表示,那么他的真子集就相当于这个点(x,y)左上方[即 0<x<xi, yi<y<maxy]的点个个数,就是比它强壮的牛的个数,然而一下子控制2个变量的变化是很耗时 的,那么我可以只控制一个变量(y),对于x我们先按x递增排序,那么所以对于每个i,i左边(0-cow[i].x)已经求过了,所以只需要 判断y上面就可以了,大量地求大范围的和我们可以用到树状数组。对于y可以直接求最大的y的值,也可以离散化y轴。


代码:离散化的解法:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 100005;
int c[MAXN], a[MAXN], temp, b[MAXN];
//树状数组,y轴离散化数组,去重之后的个数,最终结果数组
struct point
{
	int x;//x轴
	int y;//y轴
	int pos;//位置
};
point cow[MAXN];//每只牛的范围
int lowbit(int x)//树状数组函数之一
{
	return x&(-x);
}
int sum(int i)//树状数组函数之一
{
	int sum = 0;
	while (i>0)
	{
		sum += c[i];
		i -= lowbit(i);
	}
	return sum;
}
void add(int i, int val)//树状数组函数之一
{
	while (i <= temp)//temp为离散化后的y的最大值
	{
		c[i] += val;
		i += lowbit(i);
	}
}
bool cmp(point a, point b)//比较函数,按x从大到小排序
{                         //x相同时,按y递减排序
	if (a.x == b.x)
	{
		return a.y > b.y;
	}
	return a.x < b.x;
}
int main()
{
	int n;
	while (scanf("%d", &n) != EOF)
	{
		if (!n)
		{
			break;
		}
		memset(c, 0, sizeof(c));
		for (int i = 0; i < n; i++)//数据输入
		{
			scanf("%d%d", &cow[i].x, &cow[i].y);
			cow[i].pos = i;
			a[i] = cow[i].y;//y轴数据副本
		}
		sort(cow, cow + n, cmp);//排序
		sort(a, a + n);//y轴排序
		temp = unique(a, a + n) - a;//去重
		for (int i = 0; i < n; i++)//离散化
		{
			cow[i].y = upper_bound(a, a + temp, cow[i].y) - a;
			//离散化后cow[i].y的范围是1-temp
		}
		for (int i = 0; i < n; i++)
		{
			if (i)//处理特殊情况(区间重合时,不能直接求其左上方的值,因为可能会
			{     //把区间重合也算为比它大,所以要特殊处理)
				if ((cow[i].x == cow[i - 1].x) && (cow[i].y == cow[i - 1].y))
				{
					b[cow[i].pos] = b[cow[i - 1].pos];
					add(cow[i].y, 1);
					continue;
				}
			}
			b[cow[i].pos] = (sum(temp) - sum(cow[i].y - 1));
			//计算它对应坐标的左上角的个数,因为之前排序已经按x递增,所以对于每个
			//i,i左边(0-cow[i].x)已经求过了,所以只需要判断y上面就可以了
			add(cow[i].y, 1);
		}
		for (int i = 0; i < n; i++)//输出结果
		{
			printf("%d ", b[i]);
		}
		printf("\n");
	}
	return 0;
}

不离散化,直接枚举到最大的y值

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 100005;
int c[MAXN], temp, b[MAXN];
struct point
{
	int x;
	int y;
	int pos;
};
point cow[MAXN];
int lowbit(int x)
{
	return x&(-x);
}
int sum(int i)
{
	int sum = 0;
	while (i>0)
	{
		sum += c[i];
		i -= lowbit(i);
	}
	return sum;
}
void add(int i, int val)
{
	while (i <= temp)
	{
		c[i] += val;
		i += lowbit(i);
	}
}
bool cmp(point a, point b)
{
	if (a.x == b.x)
	{
		return a.y > b.y;
	}
	return a.x < b.x;
}
int main()
{
	int n;
	while (scanf("%d", &n) != EOF)
	{
		temp = 0;
		if (!n)
		{
			break;
		}
		memset(c, 0, sizeof(c));
		for (int i = 0; i < n; i++)
		{
			scanf("%d%d", &cow[i].x, &cow[i].y);
			cow[i].pos = i + 1;
			cow[i].x++;
			cow[i].y++;
			//由于x,y都可能为0,所以我统一加1,即x,y都从1开始
			temp = temp>cow[i].y ? temp : cow[i].y;
		}
		sort(cow, cow + n, cmp);
		for (int i = 0; i < n; i++)
		{
			if (i)
			{
				if ((cow[i].x == cow[i - 1].x) && (cow[i].y == cow[i - 1].y))
				{
					b[cow[i].pos] = b[cow[i - 1].pos];
					add(cow[i].y, 1);
					continue;
				}
			}
			b[cow[i].pos] = (sum(temp) - sum(cow[i].y - 1));
			add(cow[i].y, 1);
		}
		for (int i = 1; i <= n; i++)
		{
			printf("%d ", b[i]);
		}
		printf("\n");
	}
	return 0;
}

直接处理的耗时比离散化的好小,不过差距很小,基本都是1000MS


有时候可以将一维区间转换为二维点,通过加维减少问题的条件!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值