题目链接:http://poj.org/problem?id=2528
题意是:给一些海报,有左右端点li,ri,先后贴在墙上,后贴的会覆盖前面贴的,问最后能看到几张海报。
由于li,ri比较大我们离散一下,然后用线段树,对于第i张海报,把[li,ri]修改为i最后看整棵树里有多少个不一样的数字。
离散的时候注意一种情况:
1 10
1 3
5 10
这种情况如果离散为1 4 ,1 2,3 4那么就会出错。我的做法是每两个相差超过1的数字之间,再插一个数字进去。上述情况就会被 离散为1 7 , 1 3 ,5 7;
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<iostream>
using namespace std;
#define LONG long long
const int INF=0x3f3f3f3f;
const LONG MOD=1e9+61;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define lson l , mid , rt<< 1
#define rson mid + 1 ,r , (rt<<1)+1
#define root 1, m , 1
int n ;
int Num[30100][2] ;
int Discret[30010] ;
LONG tree[40100] ;
int vis[30000];
int RE[51000];
int RE1[51000] ;
LONG cov[41000];
void Push_up(int rt)
{
tree[rt] = tree[rt<<1] + tree[rt<<1|1] ;
}
void Build_tree(int l , int r , int rt)
{
cov[rt] = 0 ;
if(l == r )
{
tree[rt] = 0;
return ;
}
int mid = (l+r)/2 ;
Build_tree(lson) ;
Build_tree(rson) ;
Push_up(rt) ;
}
void Push_down(int l , int r , int rt)
{
if(cov[rt])
{
int mid = (l +r )/2;
cov[rt<<1] = cov[rt] ;
cov[rt<<1|1] = cov[rt] ;
tree[rt<<1] = (LONG )(mid - l + 1) * cov[rt] ;
tree[rt<<1|1] = (LONG ) (r - mid ) * cov[rt] ;
cov[rt] = 0 ;
}
}
void Update(int L , int R , int l, int r , int rt ,LONG val )
{
if(L <= l && r <= R)
{
tree[rt] = (LONG )(r - l + 1) * val ;
cov[rt] = val ;
return ;
}
int mid = (l + r) /2 ;
Push_down( l , r , rt) ;
if(L <= mid)
Update(L ,R ,lson, val) ;
if(R > mid)
Update(L ,R ,rson,val) ;
Push_up(rt) ;
}
LONG Query(int L , int R , int l , int r ,int rt)
{
if(L <= l && r <= R)
{
return tree[rt] ;
}
Push_down(l , r , rt) ;
LONG res = 0;
int mid = ( l + r) /2;
if(L <= mid)
res += Query( L , R , lson) ;
if( R > mid)
res += Query(L ,R , rson) ;
return res;
}
int main()
{
int T;
cin>>T;
while(T--)
{
clr0(vis) ;
scanf("%d",&n);
int m = 0 ;
for(int i = 1; i<= n ;++ i)
{
scanf("%d%d",&Num[i][0] , &Num[i][1]) ;
Discret[++m] = Num[i][0] ;
Discret[++m] = Num[i][1] ;
}
sort(Discret + 1 , Discret + m + 1) ;
int p = 0;
RE1[0] = 0 ;
//去重//
for(int i =1; i<= m ;++ i)
if(RE1[p] != Discret[i])
RE1[++ p] = Discret[i] ;
int t = 1;
RE[1] = RE1[1] ;
//避免离散化时出现问题,每两个相差超过1的数字再插一个数字进去
for(int i = 2 ; i<= p ; ++ i)
{
if(RE1[i] > RE[t] + 1)
RE[t + 1] = RE[t] + 1 ,t++;
RE[++t] = RE1[i] ;
}
sort(RE + 1 , RE + p + 1) ;
p = t;
// for(int i = 1; i <= p ; ++ i) printf("%d ",RE[i]);cout<<endl;
Build_tree( root ) ;
for(int i = 1 ; i<= n ;++ i)
{
Num[i][0] = lower_bound(RE + 1 , RE + p + 1 , Num[i][0]) - RE ;
Num[i][1] = lower_bound(RE + 1 , RE + p + 1 , Num[i][1]) - RE ;
Num[i][0] += 5 , Num[i][1] += 5 ;
Update(Num[i][0] , Num[i][1] , root , i);
}
// for(int i = 1 ; i <= n ;++ i)printf("%d %d\n",Num[i][0] , Num[i][1]) ;
for(int i = 1; i <= p ; ++ i)
{
LONG tmp = Query(i , i ,root) ;
vis[tmp] = 1;
}
int ans = 0;
for(int i = 1; i<= p ; ++i )if(vis[i]) ans ++ ;
printf("%d\n",ans);
}
return 0;
}