• poj 1769


    POJ 1769 Minimizing maximizer

    线段树之点树将最大的数字分离到最后的一位!

    题意分析如果我们考虑将数组看成一条[1, n]的线段而每项操作也看成是从[ i[k], j[k] ]的线段那么题意就是按照线段的输入顺序将线段[1, n]从左到右依次覆盖问题变成求最小的覆盖线段总数.

    算法思想考虑最基本的规划方法Opt[k] 表示覆盖掉[1, k]的线段最少需要的步数那么状态转移方程为:

    Opt[k] = min { Opt[d] + 1 | j[p] = k && d >= i[p] && d <= j[p] && k > 1 }

    其中i[p], j[p]分别表示线段p的左端点和右端点预处理: Opt[1] = 0 .

    最后的答案就是Opt[n], 但是考虑时间复杂度是O(m^2), m 最大为500000, 超时无疑.但是这里我们看到了规划的决策集合是一条连续的线段是要在这条线段上面取得最小值那么线段树的结构就正好适用.

    由于这里最小的单位是一个点所以我们采取线段树的第一种变化把元线段设置为单位点[k, k], 在规划的时候维护线段树即可.

    另外线段树结点结构中需要加入元素 xmin, 代表最少需要用到的覆盖线段数目可以覆盖到当前结点所代表的线段.

    p.s. : 如果题目不要求按照顺序选择线段从左到有覆盖的话,可以对线段进行排序,然后贪心即可.


    #include <stdio.h>
    const int N = 50001;
    const int MAX = 500001;
    struct TreeNode
    {
        int b, e; // [b, e]
        int xmin;
    }node[N*3];
    // 建立线段树(点树)
    void Bulid(int p, int l, int r)
    {
        node[p].b = l; node[p].e = r; node[p].xmin = MAX;
        if( l < r )
        {
           Bulid(p*2, l, (l+r) >> 1);
           Bulid(p*2+1, ((l+r) >> 1) + 1, r);
        }
    }
    // 维护xmin
    void Insert(int p, int r, int val)
    {
        if( node[p].xmin > val ) node[p].xmin = val;
        if( node[p].b != node[p].e )
        {
           int m = (node[p].b+node[p].e) >> 1;
           if( r <= m ) Insert(p*2, r, val);
           else Insert(p*2+1, r, val);
        }
    }
    // 取[l, r]的最小值, 以求[l, r+1]的最小值, 只需记录右端点即可
    int GetMin(int p, int l, int r)
    {
        // 如果[l, r]完全覆盖node[p], 直接返回node[p]的最小值
        if( node[p].b >= l && node[p].e <= r ) return node[p].xmin;
        int m = (node[p].b+node[p].e) >> 1;
        int t1 = MAX, t2 = MAX;
        if( r <= m ) t1 = GetMin(p*2, l, r);
        else if( l > m ) t2 = GetMin(p*2+1, l, r);
        else
        {
           t1 = GetMin(p*2, l, m);
           t2 = GetMin(p*2+1, m+1, r);
        }
        return (t1 > t2 ? t2 : t1);
    }
    int main(void)
    {
        int n, m;
        while( scanf("%d%d", &n, &m) != EOF )
        {
           Bulid(1, 1, n);   // 建树
           Insert(1, 1, 0); // opt[1] = 0;
           while( m-- )
           {
               int left, right;
               scanf("%d%d", &left, &right);
               if( left < right )
               {
                  int x = GetMin(1, left, right-1);
                  Insert(1, right, x+1); // 只更新右端点
               }
               //printf("OK!~~\n");
           }
           printf("%d\n", GetMin(1, n, n));
        }
        return 0;
    }
    

      


  • 相关阅读:
    【剑指offer】面试题 65. 不用加减乘除做加法
    【剑指offer】面试题 49. 丑数
    【剑指offer】面试题 17. 打印从 1 到最大的 n 位数
    【剑指offer】面试题 16. 数值的整数次方
    【剑指offer】面试题 15. 二进制中 1 的个数
    【剑指offer】面试题 29. 顺时针打印矩阵
    【剑指offer】面试题 28. 对称的二叉树
    InetAddress问题
    quartz与spring集成
    tomcat多项目
  • 原文地址:https://www.cnblogs.com/zhanglanyun/p/2195343.html
Copyright © 2020-2023  润新知