POJ 3264-Balanced Lineup詳解(線段樹區間求值)

kewlgrl發表於2016-04-08

Balanced Lineup

Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 43147   Accepted: 20265
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 andQ.
Lines 2..N+1: Line i+1 contains a single integer that is the height of cowi
Lines N+2..N+Q+1: Two integers A and B (1 ≤ABN), representing the range of cows from A toB 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

Source

USACO 2007 January Silver

題意是說:
給定一些座標點和值,求區間內最大最小值的差。
給定Q (1 ≤ Q ≤ 200,000)個數A1,A2 … AQ,多次求任一區間Ai– Aj中最大數和最小數的差。

只是剛學習線段樹,想說說建樹和插入。
以題目中的Input為例:

建樹。
是分割區間,遞迴建。
分割區間是指,將所有的數的個數不斷均分劃成兩顆子樹,直到L=R。
如圖:


插入:



這樣就分完了:

分別是
root,L,R,Min,Max



程式碼fromhttp://acm.pku.edu.cn/summerschool/pku_acm_train.htm

#include <iostream>
#include <cstdio>
using namespace std;
const int INF = 0xffffff0;
int minV = INF;
int maxV = -INF;
struct Node //不要左右子節點指標的做法
{
    int L, R;
    int minV,maxV;
    int Mid()
    {
        return (L+R)/2;
    }
};
Node tree[800010]; //4倍葉子節點的數量就夠
void BuildTree(int root, int L, int R) //0 1 6
{
    tree[root].L = L;
    tree[root].R = R;
    tree[root].minV = INF;
    tree[root].maxV = - INF;
    if( L != R )
    {
        BuildTree(2*root+1,L,(L+R)/2);
        BuildTree(2*root+2,(L+R)/2 + 1, R);
    }
}
void Insert(int root, int i,int v)//0 i v
//將第i個數,其值為v,插入線段樹
{
    if( tree[root].L == tree[root].R )//單值節點
    {
//成立則亦有 tree[root].R == i
        tree[root].minV = tree[root].maxV = v;
        return;
    }
    tree[root].minV = min(tree[root].minV,v);
    tree[root].maxV = max(tree[root].maxV,v);
    if( i <= tree[root].Mid() )
        Insert(2*root+1,i,v);
    else
        Insert(2*root+2,i,v);
}
void Query(int root,int s,int e)
//查詢區間[s,e]中的最小值和最大值,如果更優就記在全域性變數裡
{
    if( tree[root].minV >= minV && tree[root].maxV <= maxV )
        return;
    if( tree[root].L == s && tree[root].R == e )
    {
        minV = min(minV,tree[root].minV);
        maxV = max(maxV,tree[root].maxV);
        return ;
    }
    if( e <= tree[root].Mid())
        Query(2*root+1,s,e);
    else if( s > tree[root].Mid() )
        Query(2*root+2,s,e);
    else
    {
        Query(2*root+1,s,tree[root].Mid());
        Query(2*root+2,tree[root].Mid()+1,e);
    }
}
int main()
{
    int n,q,h;
    int i;
    scanf("%d%d",&n,&q);
    BuildTree(0,1,n);
    for( i = 1; i <= n; i ++ )
    {
        scanf("%d",&h);
        Insert(0,i,h);
    }
    for( i = 0; i <= 12; i ++ )
        cout<<i<<" "<<tree[i].L<<" "<<tree[i].R<<" "<<tree[i].minV<<" "<<tree[i].maxV<<endl;
    for( i = 0; i < q; i ++ )
    {
        int s,e;
        scanf("%d%d", &s,&e);
        minV = INF;
        maxV = -INF;
        Query(0,s,e);
        printf("%d\n",maxV - minV);
    }
    return 0;
}
/*
6 3
1
7
3
4
2
5
1 5
4 6
2 2
*/



相關文章