题意:
给了N个线段(N<=10000),现在请输出每个线段被多少个线段包围了。
[L,R]要包围线段[l,r]…则L<=l && R>=l && R-L > r-l。
思路:
先将这些线段排序,左端点升序,右端点降序。
排完以后,前面的左端点肯定不会比后面的大,要想包围,就看右端点是否比后面大。这样把右端点单独拿出来作为一个序列。能包围它的一定排在它的前面而且其右端点较大,也就是一个逆序。
要注意区间相等的情况。单独统计出来,等下一个不相等区间出现时才把之前保存下来的区间右端点进行插入。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+5;
using namespace std;
int n,m;
int C[maxn], ans[maxn];
struct Node{
int s,e, id;
bool operator < (const Node& rhs) const{
if(s != rhs.s) return s < rhs.s;
return e > rhs.e;
}
}nodes[maxn];
inline int lowbit(int x){ return x & -x; }
void add(int x, int v){for(int i = x; i <= maxn; i+= lowbit(i)) C[i]+= v;}
int sum(int x){
int s = 0;
for(int i = x; i > 0; i-= lowbit(i)) s+= C[i];
return s;
}
int main()
{
//freopen("in.txt","r",stdin);
int a,b;
while(scanf("%d",&n) == 1&&n){
memset(C, 0, sizeof(C));
for(int i = 1; i <= n; ++i){ scanf("%d%d", &a,&b); nodes[i].s = a + 1; nodes[i].e = b + 1; nodes[i].id = i; }
sort(nodes+1, nodes+n+1);
for(int i = 1; i <= n; ++i){
int v = 1, j = i;
while(j < n&&nodes[j+1].s == nodes[j].s&&nodes[j+1].e == nodes[j].e) ++v, ++j;
add(nodes[j].e, v);
ans[nodes[j].id] = j - v - sum(nodes[j].e-1);
for(; i < j; ++i) ans[nodes[i].id] = ans[nodes[j].id];
}
for(int i = 1; i < n; ++i) printf("%d ", ans[i]);
printf("%d\n", ans[n]);
}
fclose(stdin);
return 0;
}