【题解】「USACO 2007 Jan」Balanced Lineup(ST表)

题面

【题目描述】
农夫 J o h n John John N ( 1 < = N < = 50 , 000 ) N(1 <= N <= 50,000) N(1<=N<=50,000)头牛总是按同一序列排队. 有一天, J o h n John John 决定让一些牛们玩一场飞盘比赛. 他准备找一群在队列中位置连续的牛来进行比赛. 但是为了避免水平悬殊,牛的身高不应该相差太大. J o h n John John准备了 Q ( 1 < = Q < = 180 , 000 ) Q (1 <= Q <= 180,000) Q(1<=Q<=180,000)个可能的牛的选择和所有牛的身高 ( 1 < = 1 <= 1<=身高 < = 1 , 000 , 000 <= 1,000,000 <=1,000,000). 他想知道每一组里面最高和最低的牛的身高差别.
【输入】
1 1 1行: N , Q N,Q N,Q
2 2 2 N + 1 N+1 N+1行:每头牛的身高
N + 2 N+2 N+2 N + Q + 1 N+Q+1 N+Q+1行:两个整数 A A A B B B,表示从 A A A B B B的所有牛。( 1 < = A < = B < = N 1<=A<=B<=N 1<=A<=B<=N
【输出】
输出每行一个数,为最大数与最小数的差
【样例输入】

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

【样例输出】

6
3
0

算法分析

ST表模板题目。
a数组表示N头牛的身高。
f [ i ] [ j ] f[i][j] f[i][j]:表示序列 a [ i ] a[i] a[i]开始,连续 2 j 2^j 2j个数的最大值。
s [ i ] [ j ] s[i][j] s[i][j]:表示序列 a [ i ] a[i] a[i]开始,连续 2 j 2^j 2j个数的最小值。
状态转移方程:
f [ i ] [ j ] = m a x ( f [ i ] [ j − 1 ] , f [ i + 2 j − 1 ] [ j − 1 ] ) f[i][j]=max(f[i][j-1],f[i+2^{j-1}][j-1]) f[i][j]=max(f[i][j1],f[i+2j1][j1])
s [ i ] [ j ] = m i n x ( s [ i ] [ j − 1 ] , s [ i + 2 j − 1 ] [ j − 1 ] ) s[i][j]=minx(s[i][j-1],s[i+2^{j-1}][j-1]) s[i][j]=minx(s[i][j1],s[i+2j1][j1])

询问区间 a [ x ] a[x] a[x] ~ a [ y ] a[y] a[y]最大、小值?
找到一个 k k k,使得 [ x , x + 2 k − 1 ] ∪ [ y − 2 k + 1 , y ] = [ x , y ] [x , x+2^k-1 ]∪[ y-2^k+1 , y]=[x,y] [x,x+2k1][y2k+1,y]=[x,y]
需要满足: 2 k < = y − x + 1 2^k<=y-x+1 2k<=yx+1
k = l o g 2 ( y − x + 1 ) k=log_2(y-x+1) k=log2(yx+1)
区间 [ x , y ] [x,y] [x,y]最大值= m a x ( f [ x ] [ k ] , f [ y − 2 k − 1 ] [ k ] ) max( f[x][k], f[y-2^k-1][k] ) max(f[x][k],f[y2k1][k])
区间 [ x , y ] [x,y] [x,y]最小值= m i n ( s [ x ] [ k ] , s [ y − 2 k − 1 ] [ k ] ) min( s[x][k], s[y-2^k-1][k] ) min(s[x][k],s[y2k1][k])

参考程序

#include
#define N 100010
using namespace std;
int f[N][25],s[N][25];
int n,m,x,y;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&f[i][0]);
        s[i][0]=f[i][0];		//初始化
    }
         
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
            s[i][j]=min(s[i][j-1],s[i+(1<<(j-1))][j-1]); 
        }
    while(m--)
    {
        scanf("%d%d",&x,&y);
        int k=log(y-x+1)/log(2);
        printf("%d\n",max(f[x][k],f[y-(1<<k)+1][k])-min(s[x][k],s[y-(1<<k)+1][k]));
    } 
    return 0;
} 

你可能感兴趣的:(题解,数据结构)