POJ3264 Balanced Lineup 线段树|ST表

Balanced Lineup
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 39453   Accepted: 18511
Case Time Limit: 2000MS

Description

For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

Input

Line 1: Two space-separated integers,  N and  Q
Lines 2.. N+1: Line  i+1 contains a single integer that is the height of cow  i 
Lines  N+2.. N+ Q+1: Two integers  A and  B (1 ≤  A ≤  B ≤  N), representing the range of cows from  A to  B inclusive.

Output

Lines 1.. Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.

Sample Input

6 3
1
7
3
4
2
5
1 5
4 6
2 2

Sample Output

6
3
0
两种解法:
一,
最基础的线段树入门题:没有修改。
线段树知识点①:用全局变量更新结果时,只需要在包含时更新,然后根据区间中点m判断是否向左后向右走

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int maxn=50000+10;
int Max[maxn*4],Min[maxn*4];

void pushUp(int k){
    Max[k]=max(Max[k*2],Max[k*2+1]);
    Min[k]=min(Min[k*2],Min[k*2+1]);
}

void build(int k,int l,int r){
    if(l==r){
        int x;
        scanf("%d",&x);
        Max[k]=Min[k]=x;
        return ;
    }
    int m=(l+r)/2;
    build(k*2,l,m);
    build(k*2+1,m+1,r);
    pushUp(k);
}

int maxv,minv;

void ask(int a,int b,int k,int l,int r){
    if(a<=l && r<=b){
        maxv=max(maxv,Max[k]);minv=min(minv,Min[k]);
        return ;
    }
    int m=(l+r)/2;
    if(a<=m)
        ask(a,b,k*2,l,m);
    if(b>m)
        ask(a,b,k*2+1,m+1,r);
}

int main()
{
    int i,j,res,n,q;
    scanf("%d%d",&n,&q);
    build(1,1,n);
    while(q--){
        int a,b;
        scanf("%d%d",&a,&b);
        if(a>b){
            int t=a;a=b;b=t;
        }
        maxv=-1,minv=1000000+1;
        ask(a,b,1,1,n);
        printf("%d\n",maxv-minv);
    }
    return 0;
}

二、
SparseTable(ST表)
简练地总结ST算法:
f[i,j]表示以i为起点,区间长度为2^j的区间最值,此时区间为[i,i + 2^j - 1]。
②求f[i,j]时,将其分成两等份,即f[i][j-1],f[i+2^(j-1)][j-1],得f[i,j]=min(f[i][j-1],f[i+2^(j-1)][j-1])
初始态为:f[i][0]=a[i];
求f[i][j]时就采用递推,顺序是:先求区间长度为1的,再求长度为2的,再求长度为4的,即:
先求f[0][1],f[1][1],f[2][1],..,f[n][1],再求f[1][2],f[2][2],f[3][2],...,f[m][2]..,之后求f[1][3],f[2][3],...,f[k][3]
③查询时,将查询区间[a,b]分成两个可能重叠但一定能完全覆盖[a,b]的区间,即从a往后找一段,从b往前找一段,这两段的最值即答案。ans=min(f[a,k],f[b-2^k+1][k]),k为区间长度的log
②是预处理:O(nlogn) ③是查询:O(1)
具体的见:http://blog.csdn.net/insistgogo/article/details/9929103

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;

const int maxn=50000+10;
int a[maxn],fax[maxn][21],fin[maxn][21],n;

void Init(){
    int i,j,k;
    for(i=0;i<n;i++)
        fax[i][0]=fin[i][0]=a[i];
    k=int(log(double(n))/log(2.0));
    for(j=1;j<=k;j++)
        for(i=0;i<n;i++)
            if(i+(1<<j)-1<n){
                fax[i][j]=max(fax[i][j-1],fax[i+(1<<(j-1))][j-1]);
                fin[i][j]=min(fin[i][j-1],fin[i+(1<<(j-1))][j-1]);
            }
}

int cal(int l,int r){
    int k=(int)(log((double)(r-l+1))/(log(2.0)));
    int maxv=max(fax[l][k],fax[r-(1<<k)+1][k]);
    int minv=min(fin[l][k],fin[r-(1<<k)+1][k]);
    return maxv-minv;
}

int main()
{
    int x,y,i,q;
    scanf("%d%d",&n,&q);
    for(i=0;i<n;i++)
        scanf("%d",&a[i]);
    Init();
    while(q--){
        scanf("%d%d",&x,&y);
        printf("%d\n",cal(x-1,y-1));
    }
    return 0;
}


你可能感兴趣的:(poj)