题意:对于两个区间,[si,ei] 和 [sj,ej],若 si <= sj and ei >= ej and ei - si > ej - sj 则说明区间 [si,ei] 比 [sj,ej] 强。对于每个区间,求出比它强的区间的个数。
解题思路:先将每个区间按 e 降序排列,在按 s 升序排列。则对于每个区间而言,比它强的区间的区间一定位于它的前面。 利用数状数组求每个区间[si,ei]前面 满足条件的区间[sj,ej]个数(条件:ej<=ei),再减去前面的和它相同的区间的个数。 也可以利用线段树,下面附上两种代码
代码:
数状数组
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int n,MAX,c[400010],r[400010],s[400010],e[400010];
int cmp(const int x,const int y){
if(e[x] > e[y])
return 1;
else if( e[x] == e[y] )
return s[x] <= s[y];
return 0;
}
int lowbit(int x){
return x&(-x);
}
int sum(int x){
int ret = 0;
while( x > 0){
ret += c[x];
x -= lowbit(x);
}
return ret;
}
void add(int x,int d){
while(x <= MAX){
c[x] += d;
x += lowbit(x);
}
}
int main(){
int i,j,ans[100010];
while(scanf("%d",&n) == 1 && n){
MAX = 0;
for(i=0;i<n;i++){
scanf("%d%d",&s[i],&e[i]);
s[i] ++;
e[i] ++;
MAX = MAX > s[i] ? MAX : s[i];
}
for(i=0;i<n;i++)
r[i] = i;
sort(r,r+n,cmp);
memset(c,0,sizeof(c));
for(i=0;i<n;i++){
int t = r[i];
ans[t] = sum(s[t]);
add(s[t],1);
for(j=i-1;j>=0;j--)
if(e[r[j]] == e[t] && s[r[j]] == s[t])
ans[t] --;
else
break;
}
for(i=0;i<n-1;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[n-1]);
}
return 0;
}
线段树
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,MAX,r[200010],s[200010],e[200010];
struct node{
int l,r;
int value;
}a[800010];
int cmp(const int x,const int y){
if(e[x] > e[y])
return 1;
else if(e[x] == e[y])
return s[x] <= s[y];
return 0;
}
void buildtree(int i,int l,int r){
a[i].l = l;
a[i].r = r;
a[i].value = 0;
if( l== r)
return ;
int mid = (l+r) / 2 ;
buildtree(i<<1,l,mid);
buildtree((i<<1) + 1,mid+1,r);
}
int query(int i,int l,int r){
//a[i].value ++;
if(a[i].l == l && a[i].r == r)
return a[i].value ;
// a[i].value ++;
int mid = (a[i].l + a[i].r) / 2;
if(r <= mid)
return query(i<<1,l,r);
else if(l > mid)
return query((i<<1) + 1,l,r);
return query(i<<1,l,mid) + query((i<<1) + 1,mid+1,r);
}
void update(int i,int num){
a[i].value++ ;
if(a[i].l == a[i].r)
return ;
int mid = (a[i].l + a[i] .r) / 2;
if(num <= mid)
update(i<<1,num);
else
update((i<<1)+1,num);
}
int main(){
int i,j,ans[200010];
while(scanf("%d",&n) == 1 && n){
MAX = 0;
for(i=1;i<=n;i++){
scanf("%d%d",&s[i],&e[i]);
s[i] ++ ;
e[i] ++ ;
MAX = max(MAX,e[i]);
}
for(i=1;i<=n;i++)
r[i] = i;
sort(r+1,r+n+1,cmp);
buildtree(1,1,MAX);
for(i=1;i<=n;i++){
int t = r[i];
ans[t] = query(1,1,s[t]);
update(1,s[t]);
for(j=i-1;j>0;j--)
if(s[r[j]] == s[t] && e[r[j]] == e[t])
ans[t] -- ;
else
break;
}
for(i=1;i<n;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
return 0;
}