题意:给你N条线段,保证线段终点没有重复,求每条线段他包含多少条线段。
思路:将线段按左端点排序,那么问题就变成了求这条线段之后的右端点比当前右端点小的线段有几条。这样就可以拿树状数组来做,先把每条边的右
端点+1,每处理一个边,就把该边的右端点-1,那么树状数组中维护的就是该边之后的。query(r-1)就是查询当前边之后的边中右端点比当前右端点
小的边数量。因为坐标比较大,所以需要先离散化下。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
struct node
{
int l, r, ind;
bool operator <(const node &a) const
{
if(l == a.l) return r > a.r;
return l < a.l;
}
}a[maxn];
int n, num[maxn], tree[maxn], ans[maxn];
map<int, int> id;
int lowbit(int x)
{
return x&-x;
}
void update(int pos, int val)
{
while(pos < maxn)
{
tree[pos] += val;
pos += lowbit(pos);
}
}
int query(int pos)
{
int sum = 0;
while(pos)
{
sum += tree[pos];
pos -= lowbit(pos);
}
return sum;
}
int main(void)
{
while(cin >> n)
{
memset(tree, 0, sizeof(tree));
id.clear();
int cnt = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d%d", &a[i].l, &a[i].r);
a[i].ind = i;
num[cnt++] = a[i].l;
num[cnt++] = a[i].r;
}
sort(a+1, a+1+n);
sort(num, num+cnt);
int index = 1;
id[num[0]] = index++;
for(int i = 1; i < cnt; i++)
if(num[i] != num[i-1])
id[num[i]] = index++;
for(int i = 1; i <= n; i++)
update(id[a[i].r], 1);
for(int i = 1; i <= n; i++)
{
update(id[a[i].r], -1);
ans[a[i].ind] = query(id[a[i].r]-1);
}
for(int i = 1; i <= n; i++)
printf("%d\n", ans[i]);
}
return 0;
}