POJ 2481 COWS(树状数组)
题目大意:
说给你n个线段的,告诉你每个线段的起始点S_i,和终止点E_i, 问这n条线段里有多少线段是相互包含的,如果两个端点重合不算包含。
解题思路:
用树状数组搞就可以了,这道题是star的变形题,star是让我们求出有多个星星在这个星星的左下角,而这道题是让我们求出有多少个星星在这个星星的左上角。
这样分析,对于(S_i,E_i)我们把他封装成为一个点的坐标,那么(S_j,E_j)同样也可以被封装成为一个点的坐标,而题目中说的S_i<S_j&&E_j<E_i&&E_i-S_i>E_j-S_j就是说j点在i点的左上角,且两点不能重合,好了,有了这个概念,我们只需要对于y按照从大到小排序,对于相同的y我们把x从小到大排序,用树状数组来维护就好了。
代码:
# include<cstdio> # include<iostream> # include<fstream> # include<algorithm> # include<functional> # include<cstring> # include<string> # include<cstdlib> # include<iomanip> # include<numeric> # include<cctype> # include<cmath> # include<ctime> # include<queue> # include<stack> # include<list> # include<set> # include<map> using namespace std; const double PI=4.0*atan(1.0); typedef long long LL; typedef unsigned long long ULL; # define inf 999999999 # define MAX 100000+4 struct node { int x; int y; int id; }a[MAX]; int n; int ans[MAX]; int tree[MAX]; int cmp ( node a,node b ) { if ( a.y!=b.y ) return a.y > b.y; else return a.x < b.x; } int read ( int pos ) { int sum = 0; while ( pos > 0 ) { sum+=tree[pos]; pos -= pos&(-pos); } return sum; } void update ( int pos, int val ) { while ( pos <= MAX ) { tree[pos]+=val; pos += pos&(-pos); } } int main(void) { while ( cin>>n ) { memset(tree,0,sizeof(tree)); memset(ans,0,sizeof(ans)); if ( n==0 ) break; for ( int i = 0;i < n;i++ ) { scanf("%d %d",&a[i].x,&a[i].y); a[i].x++, a[i].y++; a[i].id = i; } sort(a,a+n,cmp); ans[a[0].id] = read(a[0].x); update(a[0].x,1); for ( int i = 1;i < n;i++ ) { if ( a[i].x==a[i-1].x&&a[i].y==a[i-1].y ) { ans[a[i].id]=ans[a[i-1].id]; } else { ans[a[i].id]=read(a[i].x); } update(a[i].x,1); } printf("%d",ans[0]); for ( int i = 1;i < n;i++ ) { printf(" %d",ans[i]); } printf("\n"); } return 0; }