这道题很久以前就尝试做了,后来因为那时候离散化一窍不通于是退而却步。
之后做到扫描线必须用到离散化,于是才狠下心来把离散化端了。
引用Accepted的博客的一句话“你若不想做,你会找借口;你若想做,你会找办法”。
首先讲离散化,所谓的离散化,在我看来,就是把题目中有意义的点的值抽取出来,过滤掉无意义的点,以达到节省空间甚至时间的目的。
例如我们这道题直接开数组是impossible的。所以离散是必然的选择。
在本题里,离散第一步是先把所有有用的点抽取出来放到一个数组里。
For example:对于下面这个样例
5 1 4 2 6 8 10 3 4 7 10我们抽取1 2 3 4 6 7 8 10这8个数
但是仅用这8个端点数是不符合本题的,因为正如胡浩大牛所说的那样:
普通的离散化会造成许多错误
给出下面两个简单的例子应该能体现普通离散化的缺陷:
例子一:1-10 1-4 5-10
例子二:1-10 1-4 6-10
普通离散化后都变成了[1,4][1,2][3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖
我的代码的离散化和胡浩大牛的离散化貌似有点不同,我学习的是Accepted博客的离散化。
还是拿上面两个例子,如果是我的一般的离散化的话,线段树里头就只有1 4 5 10(1 4 6 10)这4个点,将例一、例二的三条边分别加进去也会造成无法判断是否覆盖的问题。
又由于题目的每一个值代表着一个单位长度的线段,所以对于这种覆盖bug只会出现在给出的两个单位长度的线段之间还有其他线段的情况。
所以,我们只要在两个不相邻的线段间再多加一线段即可解决这问题。
附上自制低质量插图(上面是例一,最后只能看到2个海报,下面是样例二,最后应该能看到3个,但是普通离散化会把中间的第5个单位线段所表示的海报1“沉默”掉。
//插科打诨一下,不知道有没有人和我有这个相同的疑问:会不会存在一组数据使得 某一个额外加的线段 与 (离散化后)与之相邻的线段 之间的线段再次“沉默”掉,使的我们要加更多的边以防止这种再次“沉默”?For example,即有无一组数据使得1 4 (6) 10 20 中 6与10 或者 4与(6)中间的线段被再次“沉默”?
答案必然是否定的,因为我AC了((/ □ \)这算哪门子答案)
由于这个二次被沉默的线段隔壁必然是一次被沉默线段,所以如果出现二次沉默,则必然有一个数据包含一次沉默这个单位线段,而实际上这个线段是数据没有给出的。所以二次沉默不存在
插科打诨完毕//
另外,还要注意一下记录离散化的数组规模。(我因为这个RT了3,4次……)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#define lson l , mid , dex<<1
#define rson mid+1, r, dex<<1|1
#define havemid int mid = (l + r)>>1
using namespace std;
const int mx = 10100;
map<int , int> q;
struct po
{
int a,b;
int key;//The id of the poster
}point[mx];
struct se
{
int l,r;
int key;
bool flag;//Lazy flag
}seg[mx<<4];
int ini_data[mx<<1];
int aft_data[mx<<2];
void Push_down(int dex)
{
if(seg[dex].flag)
{
seg[dex<<1].flag = seg[dex<<1|1].flag = true;
seg[dex<<1].key = seg[dex<<1|1].key = seg[dex].key;
seg[dex].flag = false;
}
}
void build(int l, int r, int dex)
{
seg[dex].l = aft_data[l];
seg[dex].r = aft_data[r];
seg[dex].key = -1;
seg[dex].flag = false;
if(l == r) return;
havemid;
build(lson);
build(rson);
}
void query(int l, int r, int dex, int& ans)
{
if(seg[dex].l == seg[dex].r)
{
if(q[seg[dex].key] == 0 && seg[dex].key != -1)
{
ans++;
q[seg[dex].key] = 1;
}
return;
}
Push_down(dex);
havemid;
query(lson, ans);
query(rson, ans);
}
void updata(int L, int R, int id, int l, int r, int dex)
{
if(R < seg[dex].l || L > seg[dex].r) return;
if(L<=seg[dex].l && R>=seg[dex].r)
{
seg[dex].key = id;
seg[dex].flag = true;
return;
}
Push_down(dex);
havemid;
updata(L, R, id, lson);
updata(L, R, id, rson);
}
int main()
{
// freopen("2528.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
q.clear();
int n;
scanf("%d",&n);
int tem = 0;
for(int i=1; i<=n; i++)
{
scanf("%d%d",&point[i].a,&point[i].b);
point[i].key = i;
ini_data[++tem] = point[i].a;
ini_data[++tem] = point[i].b;
}
//Disperse the segmemt
sort(&ini_data[1] , &ini_data[tem+1]);
int w = 0;
ini_data[0] = -1;
for(int i=1; i<=tem; i++)
if(ini_data[i] != ini_data[i-1])
ini_data[++w] = ini_data[i];
tem = w;
w = 0;
aft_data[++w] = ini_data[1];
for(int i=2; i<=tem; i++)
{
if(ini_data[i] > ini_data[i-1] + 1)
{
aft_data[++w] = ini_data[i] - 1;
aft_data[++w] = ini_data[i];
}
else
aft_data[++w] = ini_data[i];
}
build(1,w,1);
for(int i=1; i<=n; i++)
updata(point[i].a, point[i].b, point[i].key, 1, w, 1);
int ans = 0;
query(1, w ,1, ans);
printf("%d\n",ans);
}
return 0;
}