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; }