1. 程式人生 > >【HDU 1754】I Hate It

【HDU 1754】I Hate It

Problem  Description:

很多學校流行一種比較的習慣。老師們很喜歡詢問,從某某到某某當中,分數最高的是多少。
這讓很多學生很反感。
不管你喜不喜歡,現在需要你做的是,就是按照老師的要求,寫一個程式,模擬老師的詢問。當然,老師有時候需要更新某位同學的成績。

Input:

本題目包含多組測試,請處理到檔案結束。
在每個測試的第一行,有兩個正整數 N 和 M ( 0<N<=200000,0<M<5000 ),分別代表學生的數目和操作的數目。
學生ID編號分別從1編到N。
第二行包含N個整數,代表這N個學生的初始成績,其中第i個數代表ID為i的學生的成績。
接下來有M行。每一行有一個字元 C (只取'Q'或'U') ,和兩個正整數A,B。
當C為'Q'的時候,表示這是一條詢問操作,它詢問ID從A到B(包括A,B)的學生當中,成績最高的是多少。
當C為'U'的時候,表示這是一條更新操作,要求把ID為A的學生的成績更改為B。

Output:

對於每一次詢問操作,在一行裡面輸出最高成績。

Sample  Input:

5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5

Sample  Output:

5
6
5
9

思路:這道題可以用樹狀陣列、線段樹都可以,都是單點更新,區間求最大值的過程。

其中用樹狀陣列方法時需要注意查詢的過程,要活用查詢操作。從R開始查詢,然後通過R - lowbit [ R ] 進行一個區間一個區間的查詢來減少時間複雜度,但是如果要查詢的區間的左界比L小,就只對此單點進行查詢,再進行下一個區間的查詢,直到查詢到L的位置。

下面是2種方法的程式碼。

My  DaiMa(樹狀陣列):

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
int a[200005],build[200005],lowbit[200005],n;
void GetLowbit()
{
    for(int i = 1; i <= n ; i++)
        lowbit[i] = i&(-i);
}
///建樹,先求出每一段的初始最大值存在build數組裡
void TreeBuild()
{
    for(int i = 1; i <= n; i++)
    {
        build[i] = a[i];
        for(int j = i-1; j > i-lowbit[i]; j--)
            build[i] = max(build[i],a[j]);
    }
}
///單點更新,更新所有管轄到x的build值
void update(int x, int y)
{
    a[x] = y;
    for(int i = x; i <= n; i += lowbit[i])
        build[i] = max(build[i],a[x]);
}
///查詢
int Find_max(int x,int y)
{
    int maxx = a[y];///從區間右邊開始
    while(y != x)
    {
        for(y -= 1; y-lowbit[y] > x; y -= lowbit[y])///根據lowbit進行一個區間一個區間的查詢
            maxx = max(maxx,build[y]);
        maxx = max(maxx,a[y]);///當查詢的區間的左界小於x時,只對單點進行查詢
    }
    return maxx;
}
int main()
{
    int m;
    char ch;
    while(cin >> n >> m)
    {
        for(int i = 1; i <= n; i++)
            scanf("%d",&a[i]);
        GetLowbit();
        TreeBuild();
        int x,y;
        while(m--)
        {
            cin >> ch >> x >> y;
            if(ch == 'U') update(x,y);///單點更新
            else cout << Find_max(x,y) << endl;///查詢區間最大值
        }
    }
}

My  DaiMa(線段樹):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f
#define MAX 200005
using namespace std;
#define lson l,mid,num<<1
#define rson mid+1,r,num<<1|1
int value[MAX<<2];
void push_up(int num)
{
    value[num] = max(value[num<<1],value[num<<1|1]);
}
///建樹
void TreeBuild(int l,int r,int num)
{
    if(l == r)
    {
        scanf("%d",&value[num]);
        return;
    }
    int mid = (l+r) >> 1;
    TreeBuild(lson);
    TreeBuild(rson);
    push_up(num);///別忘了這一步
}
///單點更新
void update(int x,int y,int l,int r,int num)
{
    if(l == x && r == x)
    {
        value[num] = y;
        return;
    }
    int mid = (l+r) >> 1;
    if(x <= mid) update(x,y,lson);
    else update(x,y,rson);
    push_up(num);///別忘了這一步
}
///區間查詢最大值
int query(int L,int R,int l,int r,int num)
{
    if(L <= l && R >= r) return value[num];
    int maxn = 0;
    int mid = (l+r) >> 1;
    if(L <= mid) maxn = max(maxn,query(L,R,lson));
    if(R > mid) maxn = max(maxn,query(L,R,rson));
    return maxn;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        TreeBuild(1,n,1);
        char ch[3];
        int x,y;
        while(m--)
        {
            scanf("%s%d%d",ch,&x,&y);
            if(ch[0] == 'U') update(x,y,1,n,1);
            else printf("%d\n",query(x,y,1,n,1));
        }
    }
}