线段树,线段树一般是对连续的区块进行操作,每次给出相应的区块,但是本题给出海报覆盖的是区间,要把区间对应到区块上。虽然有些情况还不能处理,但是过了。
#include < iostream >
#include < cstdio >
#include < cstdlib >
#include < cstring >
#include < algorithm >
using namespace std;
#define maxn 20005
struct Interval
{
int s, e;
}interval[maxn];
struct Node
{
Node * pleft, * pright;
int l, r;
bool full;
}tree[maxn * 3 ];
int pos[maxn * 2 ], poscount, ncount;
void buildtree(Node * proot, int l, int r)
{
proot -> l = l;
proot -> r = r;
if (l == r)
return ;
int mid = (l + r) / 2 ;
ncount ++ ;
proot -> pleft = tree + ncount;
ncount ++ ;
proot -> pright = tree + ncount;
buildtree(proot -> pleft, l, mid);
buildtree(proot -> pright, mid + 1 , r);
}
bool paste(Node * proot, int l, int r)
{
if (l == r)
return false ;
if (proot -> full)
return false ;
if (proot -> l == l && proot -> r == r - 1 )
{
proot -> full = true ;
return true ;
}
int mid = (proot -> l + proot -> r) / 2 ;
bool ret;
if (r <= mid + 1 )
ret = paste(proot -> pleft, l, r);
else if (l > mid)
ret = paste(proot -> pright, l, r);
else
{
ret = paste(proot -> pleft, l, mid + 1 );
ret = paste(proot -> pright, mid + 1 , r) || ret;
}
proot -> full = proot -> pleft -> full && proot -> pright -> full;
return ret;
}
int binarysearch( int a)
{
int l = 0 ;
int r = poscount - 1 ;
while (l < r)
{
int mid = (l + r) / 2 ;
if (pos[mid] >= a)
r = mid;
else
l = mid + 1 ;
}
return l;
}
int main()
{
// freopen("t.txt", "r", stdin);
int t;
scanf( " %d " , & t);
while (t -- )
{
poscount = 0 ;
ncount = 0 ;
memset(tree, 0 , sizeof (tree));
int n;
scanf( " %d " , & n);
for ( int i = 0 ; i < n; i ++ )
{
scanf( " %d%d " , & interval[i].s, & interval[i].e);
pos[poscount ++ ] = interval[i].s;
pos[poscount ++ ] = interval[i].e;
}
sort(pos, pos + poscount);
poscount = unique(pos, pos + poscount) - pos;
buildtree(tree, 0 , poscount - 1 );
int ans = 0 ;
for ( int i = n - 1 ; i >= 0 ; i -- )
{
int s = binarysearch(interval[i].s);
int e = binarysearch(interval[i].e) + 1 ;
if (paste(tree, s, e))
ans ++ ;
}
printf( " %d\n " , ans);
}
return 0 ;
}