POJ 2481 Cows(树状数组)
http://poj.org/problem?id=2481
题意:
有n头牛,每头牛对应一个区间[Si,Ei],如果牛j 的区间是牛i 的区间的真子集(即Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj),那么就说牛i 比牛j 强壮。要你依次输出比第i头牛强壮的牛数目。
分析:
对于任意两头牛i和j,只有当Si <= Sjand Ej <= Ei and Ei - Si > Ej – Sj时,i才比j强壮,即:
如果将所有牛的E区间按从大到小排序(如果E相同,则S小的排在前面)的话,那当前读取到第i个牛的Si和Ei,那么之前(假设任意牛的区间不会完全相同)的牛的Sj(j<=i-1)<=Si的这些牛就都比i号牛强壮了。
所以我们首先对读取到的区间排序,然后可以用树状数组利用牛的S坐标来算出结果。
本题难点:如果两个区间完全一样,那么这两头牛不能互为强壮。但是这两头牛对后面的更弱的牛有用。
我的解决方法是:如果第i头牛与第i-1头牛完全相同,那么就用i-1的结果赋值给i的结果。如果i牛与i-1牛不完全相同,就输出前面有多少牛的S值<=S[i]。需要注意的是,牛的S和E坐标可能为0,所以我们对读取的S和E坐标都+1,整体后移一格。
AC代码:891ms
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=100000+1000;
int c[MAXN];
int lowbit(int x)
{
return x&(-x);
}
int sum(int x)//x>=1
{
int res=0;
while(x>0)
{
res +=c[x];
x-=lowbit(x);
}
return res;
}
void add(int x,int v)//x>=1
{
while(x<=MAXN)
{
c[x] +=v;
x+=lowbit(x);
}
}
struct cow
{
int s,e;
int index;
bool operator <(const cow&b)const//e值越大越靠前,e值相同时s值越小越靠前
{
return e>b.e||(e==b.e&&s<b.s);
}
}cows[MAXN];
int ans[MAXN];//ans[i]=x 表有x头牛比i号牛强壮
int main()
{
int n;
while(scanf("%d",&n)==1&&n)
{
for(int i=0;i<n;i++)
{
int s,e;
scanf("%d%d",&s,&e);
s++;//以防s值为0
cows[i].s=s;
cows[i].e=e;
cows[i].index=i;//保存初始序号
}
sort(cows,cows+n);
memset(ans,0,sizeof(ans));
memset(c,0,sizeof(c));
ans[cows[0].index]=0;//单独处理重新排序后的第0个牛
add(cows[0].s,1);
for(int i=1;i<n;i++)
{
if(cows[i].s==cows[i-1].s && cows[i].e==cows[i-1].e)//两头牛的区间完全一样
ans[cows[i].index] = ans[cows[i-1].index];
else //新的牛区间,与之前的牛区间不同
ans[cows[i].index] = sum(cows[i].s);
add(cows[i].s,1);
}
for(int i=0;i<n;i++)
printf("%d ",ans[i]);
printf("\n");
}
return 0;
}