• 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;
    }

  • 相关阅读:
    通过Logstash由SQLServer向Elasticsearch同步数据
    ELK +Nlog 分布式日志系统的搭建 For Windows
    Gulp 给所有静态文件引用加版本号
    Fluentdata详解
    jQuery Easy UI (适应屏幕分辨率大小)布局(Layout)
    什么是数据结构---算法
    WCF的学习之旅
    程序员必学之精华----软件工程
    译 .NET Core 3.0 发布
    Vue+Element UI 实现视频上传
  • 原文地址:https://www.cnblogs.com/vongang/p/2133869.html
Copyright © 2020-2023  润新知