大致题意:
有一面墙,被等分为1QW份,一份的宽度为一个单位宽度。现在往墙上贴N张海报,每张海报的宽度是任意的,但是必定是单位宽度的整数倍,且<=1QW。后贴的海报若与先贴的海报有交集,后贴的海报必定会全部或局部覆盖先贴的海报。现在给出每张海报所贴的位置(左端位置和右端位置),问张贴完N张海报后,还能看见多少张海报?(PS:看见一部分也算看到。)
解题思路:
水题,区间压缩映射(离散化)+ 线段树
首先建立模型:
给定一条数轴,长度为1QW,然后在数轴上的某些区间染色,第i次对区间染色为i,共染色N次。给出每次染色的区间,问最后能看见多少种颜色。
离散化就是压缩区间,使原有的长区间映射到新的短区间,但是区间压缩前后的覆盖关系不变。举个例子:
有一条1到10的数轴(长度为9),给定4个区间[2,4] [3,6] [8,10] [6,9],覆盖关系就是后者覆盖前者,每个区间染色依次为 1 2 3 4。
现在我们抽取这4个区间的8个端点,2 4 3 6 8 10 6 9
然后删除相同的端点,这里相同的端点为6,则剩下2 4 3 6 8 10 9
对其升序排序,得2 3 4 6 8 9 10
然后建立映射
2 3 4 6 8 9 10
↓ ↓ ↓ ↓ ↓ ↓ ↓
1 2 3 4 5 6 7
那么新的4个区间为 [1,3] [2,4] [5,7] [4,6],覆盖关系没有被改变。新数轴为1到7,即原数轴的长度从9压缩到6,显然构造[1,7]的线段树比构造[1,10]的线段树更省空间,搜索也更快,但是求解的结果却是一致的。
离散化时有一点必须要注意的,就是必须先剔除相同端点后再排序,这样可以减少参与排序元素的个数,节省时间。
附:海报张数上限为10000,即其端点映射的新数轴长度最多为20000。因此建立长度为1QW的离散数组dis时,可以使用unsigned short类型,其映射值最多为20000,这样可以节约空间开销。
/******************
* Author :fisty
* data: 2014-10-26
* poj2528
* 线段树成段更新
* ******************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
#define MID(a,b) (a+((b-a)>>1))
const int N=20005;
struct node
{
int lft,rht,co;
int mid(){return MID(lft,rht);}
};
int a[N],b[N],n;
vector<int> y;
bool flag[N/2];
map<int,int> H;
struct Segtree
{
node tree[N*4];
void build(int l,int r,int k)
{
tree[k].lft=l;
tree[k].rht=r;
tree[k].co=0;
if(l + 1 != r)
{
int mid=tree[k].mid();
build(l, mid, k << 1);
build(mid, r, k << 1 | 1);
}
}
void updata(int st,int ed,int k,int co)
{
if(st <= tree[k].lft && tree[k].rht <= ed) tree[k].co=co;
else
{
if(tree[k].co)
{
tree[k << 1].co=tree[k].co;
tree[k << 1|1].co=tree[k].co;
tree[k].co=0;
}
int mid=tree[k].mid();
//注意,这里与单点更新时不同。要分在左边,在右边,因为是区间所以要考虑跨区间情况
if(st < mid)
updata(st, ed, k << 1,co);
if(ed > mid)
updata(st, ed, k << 1 | 1, co);
}
}
void query(int st,int ed,int k)
{
int l=tree[k].lft,r=tree[k].rht;
if(tree[k].co != 0 || l + 1 == r)
{
flag[tree[k].co]=1;
return;
}
query(st,ed,k << 1); query(st,ed, k << 1 | 1);
}
}seg;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
y.clear(); H.clear();
scanf("%d",&n);
for(int i=0;i<n;i++)
{
flag[i]=0;
scanf("%d%d",&a[i],&b[i]);
b[i]++;
y.push_back(a[i]); y.push_back(b[i]);
}
sort(y.begin(),y.end());
y.erase(unique(y.begin(),y.end()),y.end());
for(int i = 0;i < (int)y.size(); i++) H[y[i]]=i;
int len = (int)y.size();
seg.build(0, len-1, 1);
for(int i=0;i<n;i++) seg.updata(H[a[i]],H[b[i]],1,i+1);
seg.query(1,len,1);
int res=0;
for(int i=1;i<=n;i++) if(flag[i]) res++;
printf("%d\n",res);
}
return 0;
}