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; //右端点(这里与前边输入时对应)
}

这个操作完成之后直接更新就可以了。

下边是完整的代码:

View Code
#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;
}

posted @ 2011-08-10 17:05  AC_Von  阅读(1035)  评论(0编辑  收藏  举报