线段树,线段树一般是对连续的区块进行操作,每次给出相应的区块,但是本题给出海报覆盖的是区间,要把区间对应到区块上。虽然有些情况还不能处理,但是过了。
View Code
#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;
}