题意:有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
有时候可以将一维区间转换为二维点,通过加维减少问题的条件!