You are given n segments on a line. There are no ends of some segments that coincide. For each segment find the number of segments it contains.
The first line contains a single integer n (1 ≤ n ≤ 2·105) — the number of segments on a line.
Each of the next n lines contains two integers li and ri ( - 109 ≤ li < ri ≤ 109) — the coordinates of the left and the right ends of the i-th segment. It is guaranteed that there are no ends of some segments that coincide.
Print n lines. The j-th of them should contain the only integer aj — the number of segments contained in the j-th segment.
4 1 8 2 3 4 7 5 6
3 0 1 0
3 3 4 1 5 2 6
0 1 1
题目大意:
给你N个线段,保证线段的起点和终点没有重复(一个点只能作为一个起点或者终点),一共N个询问,问每个线段可以包含多少个线段。
思路:
1、对于N个线段来讲,我们先将所有线段按照l从小到大排序,那么问题就变成了:询问一个线段后边,有多少个线段的bl小于ar,并且br也小于ar,其实就是有多少个线段的br小于ar.因为如果一个线段的r小于了这个线段的r,而且现在l是从小到大排序的,那么这个线段b一定是线段a所包含的。
2、那么问题可以用树状数组来维护。
然而数据范围是比较大的,所以我们再套个离散化即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
using namespace std;
#define N 1000000
struct node
{
int l,r,pos;
}a[1200000];
int num[1200000];
int tree[1004005];//树
int ans[1000500];
int cmp(node a,node b)
{
if(a.l!=b.l)
return a.l<b.l;
else return a.r<b.r;
}
int lowbit(int x)//lowbit
{
return x&(-x);
}
int sum(int x)//求和求的是比当前数小的数字之和,至于这里如何实现,很简单:int sum=sum(a[i]);
{
int sum=0;
while(x>0)
{
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
void add(int x,int c)//加数据。
{
while(x<=N)
{
tree[x]+=c;
x+=lowbit(x);
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
int cnt=0;
memset(tree,0,sizeof(tree));
for(int i=0;i<n;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].pos=i;
num[cnt++]=a[i].l;
num[cnt++]=a[i].r;
}
map<int ,int >s;
int contz=1;
sort(num,num+cnt);
sort(a,a+n,cmp);
for(int i=0;i<cnt;i++)
{
if(s[num[i]]==0)
{
s[num[i]]=contz;
contz++;
}
}
for(int i=0;i<n;i++)add(s[a[i].r],1);
for(int i=0;i<n;i++)
{
add(s[a[i].r],-1);
ans[a[i].pos]=sum(s[a[i].r]-1);
}
for(int i=0;i<n;i++)printf("%d\n",ans[i]);
}
}