• POJ3264 Balanced Lineup---线段树


    岳父与小明:农夫约翰有N头牛排成一列,他从第A头牛到第B头牛里挑出最高的那头取名叫岳父,最矮的那头取名叫小明。求岳父与小明的身高差?

    给出初始化的区间值,m次查询
    每次查询区间[a,b]的最大值-最小值

    题目大意:   给出初始化的区间值,m次查询

                      每次查询区间[a,b]的最大值-最小值

    解题思路:   线段树    更新: 无更新    查询:区间查询

                      建立线段树的时候,每个结点存储左右子树的最大值和最小值

                      查询时直接访问区间最大值和最小值,不需要查找到最低

                      查询时间复杂度O(logN)

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define MAXN 70000
    #define INF 0x3f3f3f3f
    #define MAX(a,b) a>b?a:b
    #define MIN(a,b) a<b?a:b
    #define MID(a,b) (a+b)>>1
    #define L(a) a<<1
    #define R(a) (a<<1)+1
    
    typedef struct snode{
        int left,right;
        int max,min;
    }Node;
    
    Node Tree[MAXN<<1];
    int num[MAXN],minx,maxx;
    
    void Build(int t,int l,int r)    ///以t为根结点建立左子树为l,右子树为r的线段树
    {
        int mid;
        Tree[t].left=l,Tree[t].right=r;
        if(Tree[t].left==Tree[t].right)///区间变为点
        {
            Tree[t].max=Tree[t].min=num[l];
            return ;
        }
        mid=MID(Tree[t].left,Tree[t].right);
        Build(L(t),l,mid);///左右子树
        Build(R(t),mid+1,r);
        Tree[t].max=MAX(Tree[L(t)].max,Tree[R(t)].max);  ///更新结点的最大值=MAX(左子树,右子树)
        Tree[t].min=MIN(Tree[L(t)].min,Tree[R(t)].min);  ///更新结点的最小时=MIN(左子树,右子树)
    }
    
    void Query(int t,int l,int r)    ///查询结点为t,左子树为l,右子树为r的最大值和最小值
    {
        int mid;
        if(Tree[t].left==l&&Tree[t].right==r)
        {
            if(maxx<Tree[t].max)
                maxx=Tree[t].max;
            if(minx>Tree[t].min)
                minx=Tree[t].min;
            return ;
        }
        mid=MID(Tree[t].left,Tree[t].right);
        if(l>mid)
        {
            Query(R(t),l,r);
        }
        else if(r<=mid)
        {
            Query(L(t),l,r);
        }
        else
        {
            Query(L(t),l,mid);
            Query(R(t),mid+1,r);
        }
    }
    
    int main()
    {
        int n,m,a,b,i;
        memset(Tree,0,sizeof(Tree));
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
            scanf("%d",&num[i]);
        Build(1,1,n);            ///建立以1为根结点区间为[1,n]的线段树
        while(m--)
        {
            scanf("%d%d",&a,&b);
            maxx=0;minx=INF;     ///初始化最大值为0,最小值为INF
            Query(1,a,b);        ///查询区间[a,b]的最大值和最小值
            printf("%d
    ",maxx-minx);
        }
        return 0;
    }

    线段树和平方分割

    平方分割我觉得是一种分治的思想,它所追求的不是分治的最终结果,而是过程的中间结果。将这N头牛平方分割放入sqrt(N)个桶,每个桶只需记录桶里最高和最矮的两个身高值即可。然后完全包含在区间的桶里直接考虑这两个值,否则从原始数据里比较。

    唯一需要注意的是这里的下标问题,下标从零开始的话,在求模的时候需要注意:左边界 mod bucket_size == 0时左边界恰好落入桶,(右边界 + 1) mod bucket_size == 0时右边界才恰好落入桶,两者不一样的。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    #include "cstdio"
    using namespace std;
    #define MAX_N 50000 + 16
    
    int H[MAX_N];    // 输入N头牛的高度
    vector<pair<int, int> > bucket; // 对每个桶内高度的最小值与最大值的记录
    
    ///////////////////////////SubMain//////////////////////////////////
    int main(int argc, char *argv[])
    {
    #ifndef ONLINE_JUDGE
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
    #endif
        int N, Q;
        scanf("%d%d", &N, &Q);
        const int bucket_size = sqrt((float)N);    // error C2668: 'sqrt' : ambiguous call to overloaded function
        bucket.resize(bucket_size + 1);
        for (int i = 0; i < bucket_size + 1; ++i)
        {
            bucket[i].first = 0x3f3f3f3f;
            bucket[i].second = 0x80808080;
        }
        for (int i = 0; i < N; ++i)
        {
            scanf("%d", &H[i]);
            bucket[i / bucket_size].first  = min(bucket[i / bucket_size].first, H[i]);
            bucket[i / bucket_size].second = max(bucket[i / bucket_size].second, H[i]);
        }
    
        for (int i = 0; i < Q; ++i)
        {
            int A, B;
            scanf("%d%d", &A, &B);
            if (A == B)
            {
                puts("0");
                continue;
            }
            int min_height = 0x3f3f3f3f;
            int max_height = 0x80808080;
            int l = A - 1, r = B;
            // 区间两端多出来的部分
            while (l < r && l % bucket_size != 0)
            {
                int h = H[l++];
                min_height = min(min_height, h);
                max_height = max(max_height, h);
            }
            while (l < r && r % bucket_size != 0)
            {
                int h = H[--r];
                min_height = min(min_height, h);
                max_height = max(max_height, h);
            }
    
            // 对每一个桶进行计算
            while (l < r)
            {
                int b = l / bucket_size;
                min_height = min(min_height, bucket[b].first);
                max_height = max(max_height, bucket[b].second);
                l += bucket_size;
            }
            printf("%d
    ", max_height - min_height);
        }
        /*
    #ifndef ONLINE_JUDGE
        fclose(stdin);
        fclose(stdout);
        system("out.txt");
    #endif*/
        return 0;
    }
  • 相关阅读:
    美国首位女计算机博士荣获今年图灵奖
    此人需要关注一下
    Microsoft的壮大与IBM对Sun的收购
    文章介绍:Sexy Lexing with Python
    程序员的门道
    闲谈:敏捷与否的区分方法、对组织内部人员的现实作用与长远利益
    聊聊最俗的工厂相关话题
    人之患在好为人师
    TIOBE的头头儿和“反Java”的教授
    敏捷的核心究竟是什么
  • 原文地址:https://www.cnblogs.com/kimsimple/p/6863137.html
Copyright © 2020-2023  润新知