http://poj.org/problem?id=2481
题意:这里就是求区间覆盖问题,求每个区间被多少区间覆盖,相同两个区间的不算。
思路:线段数,先将所有区间 [l, r] 按照 r 位置降序排列,然后将线段树中 l 位置的 sum + 1,插入后统计[0, l] 区间的和。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;/
const int maxn = 100005;
struct node{
int id, l, r, sum;
friend bool operator < (node a, node b){
return a.r > b.r || (a.r == b.r && a.l < b.l);
}
};
int n;
int sta[maxn];
node mapn[maxn];
node tr[maxn<<2];
int Build(int rt, int l, int r) //构建线段树
{
tr[rt].l = l;
tr[rt].r = r;
tr[rt].sum = 0;
if(l == r)
return 0;
int mid = (l + r) >> 1;
Build(rt<<1, l, mid);
Build(rt<<1|1, mid + 1, r);
return 0;
}
int Insert(int rt, int x, int val) //将 x 位置的 sum 加上val
{
if(tr[rt].l > x || tr[rt].r < x)
return tr[rt].sum;
if(tr[rt].l == tr[rt].r){
tr[rt].sum += val;
return tr[rt].sum;
}
tr[rt].sum = Insert(rt<<1, x, val) + Insert(rt<<1|1, x, val);
return tr[rt].sum;
}
int query(int rt, int l, int r) //查询
{
if(tr[rt].l > r || tr[rt].r < l)
return 0;
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].sum;
return query(rt<<1, l, r) + query(rt<<1|1, l, r);
}
int main()
{
while(scanf("%d", &n) && n){
int len = -1;
for(int i = 0; i < n; i++){
mapn[i].id = i;
scanf("%d%d", &mapn[i].l, &mapn[i].r);
if(mapn[i].r > len)
len = mapn[i].r;
}
sort(mapn, mapn+n);
Build(1, 0, len);
int sum = 1;
for(int i = 0; i < n; i++){
sta[mapn[i].id] = query(1, 0, mapn[i].l); //先查询
if(mapn[i].l == mapn[i+1].l && mapn[i].r == mapn[i+1].r){
sum++;
continue; //避免将相同的计算进去,所以先不插入
}
Insert(1, mapn[i].l, sum); //最后一个插入,避免重复
sum = 1;
}
for(int i = 0; i < n; i++){
printf("%d ",sta[i]);
}
printf("\n");
}
return 0;
}