POJ_2528 Mayor's posters(线段树+离散化)
线段树“以点代段”的思想很巧妙,但有时候数据过大直接建线段树会MLE,就比如这道题,如果不进行优化的话肯定是要MLE的(1 <= li <= ri <= 10000000,这得多大的内存消耗啊)。所以,离散化这个概念被引入,离散化这个词最近经常听,但就是不知道具体如何实现,今天借这道题学习了一下,这里写点总结。
比如说这样一串数(3,10000),(9,1000000),(5,100000),(1,1000),(7,1000000);用这组数据直接更新线段树,很有可能会挂掉的(不信可以自己试试。。。)。但如果在不影响线段树更新状态的前提下,把这几个大数用相应的小数取代,再更新的话,会使内存消耗大大减小。
先给这几个数找到对应的值,比如可以这样:(3,4),(9,10),(5,6),(1,2),(7,8);最大值由1000000减小到10,缩小了100000。怎么至于怎么实现这个过程呢?今天学到了一种很巧妙的方法:
先定义一个结构体:
struct po
{
int p; //存放端点值
int num; //存放端点位置(左端点还是右端点)
}po[N*2];
先定义一个数组 F[N][3];用来读取各段的端点,然后将端点信息存到结构体中:
for(i = 1; i <= n; i++)
{
scanf("%d%d", &f[i][0], &f[i][1]);
po[2*i-1].p = f[i][0]; //左端点的值
po[2*i-1].num = i; //标记为左端点
po[2*i].p = f[i][1]; //右端点的值
po[2*i].num = -1*i; //标记为右端点(用正负号区分)
}
然后按端点从小到大排序,得到一串连续的数,现在就要将值离散化了(注意,可能有重复的点!需要排除在外):
int t = 1; //用来给离散化后的数赋新值
int tmp = po[1].p; //判断是否重复
for(i = 1; i <= 2*n; i++)
{
if(tmp != po[i].p) //如果不重复
{
tmp = po[i].p;
t++; //出现新的点,则赋值+1
}
if(po[i].num > 0)
f[po[i].num][0] = t; //左端点
else
f[-1*po[i].num][1] = t; //右端点(这里与前边输入时对应)
}
这个操作完成之后直接更新就可以了。
下边是完整的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define L(x) (x << 1)
#define R(x) (x << 1 | 1)
#define N 10010
struct node
{
int l, r;
int c;
}node[N*14];
struct po
{
int p;
int num;
}po[N*2];
int flag[N*4], num;
int cmp(const void *a, const void *b)
{
struct po * c = (struct po *)a;
struct po * d = (struct po *)b;
return c->p - d->p;
}
void creat(int t, int l, int r)
{
node[t].l = l;
node[t].r = r;
node[t].c = 0;
if(l == r) return;
int mid = (node[t].l + node[t].r) >> 1;
creat(L(t),l, mid);
creat(R(t), mid + 1, r);
}
void updata(int t, int l, int r, int c)
{
if(node[t].l >= l && node[t].r <= r)
{
node[t].c = c;
return;
}
if(node[t].c > 0)
{
node[L(t)].c = node[t].c;
node[R(t)].c = node[t].c;
node[t].c = 0;
}
int mid = (node[t].l + node[t].r) >> 1;
if(l > mid)
updata(R(t), l, r, c);
else if(r <= mid)
updata(L(t), l, r, c);
else
{
updata(L(t), l, mid, c);
updata(R(t), mid + 1, r, c);
}
}
void count(int t)
{
if(node[t].c > 0)
{
if(flag[node[t].c] == 0)
{
num++;
flag[node[t].c]++;
}
return;
}
if(node[t].l == node[t].r)
return;
count(L(t));
count(R(t));
}
int main()
{
int f[N][3];
int t, n, i;
//freopen("data.in", "r", stdin);
while(~scanf("%d",&t))
{
while(t--)
{
memset(flag, 0, sizeof(flag));
memset(f, 0, sizeof(f));
scanf("%d", &n);
for(i = 1; i <= n; i++)
{
scanf("%d%d", &f[i][0], &f[i][1]);
po[2*i-1].p = f[i][0];
po[2*i-1].num = i;
po[2*i].p = f[i][1];
po[2*i].num = -1*i;
}
qsort(po+1, 2*n, sizeof(po[1]), cmp);
int t = 1, tmp = po[1].p;
for(i = 1; i <= 2*n; i++)
{
if(tmp != po[i].p)
{
tmp = po[i].p;
t++;
}
if(po[i].num > 0)
f[po[i].num][0] = t;
else
f[-1*po[i].num][1] = t;
}
creat(1, 1, t);
for(i = 1; i <= n; i++)
{
//printf("%d %d\n", f[i][0], f[i][1]);
updata(1, f[i][0], f[i][1], i);
}
num = 0;
count(1);
printf("%d\n",num);
}
}
return 0;
}