1. 程式人生 > >Luogu P1198 BZOJ 1012 最大數 (線段樹)

Luogu P1198 BZOJ 1012 最大數 (線段樹)

繼續 編號 UNC space 添加 大數 表示 線段樹 mod

手動博客搬家: 本文發表於20170821 14:32:05, 原地址https://blog.csdn.net/suncongbo/article/details/77449455

URL: (Luogu) https://www.luogu.org/problem/show?pid=1198, (BZOJ)http://www.lydsy.com/JudgeOnline/problem.php?id=1012

題目大意:
給定一個數列,開始為空。維護兩種操作:

(1) Q L表示查詢當前數列後L個數的最大值。

(2) A N表示在當前數列末尾添加一個新數,這個新數的值等於上一次Q操作的答案加上給定的參數N. 若之前未進行Q操作,則添加的數為N.

思路分析:
此題牽扯到區間最值,我們可以用線段樹進行解決。
但是Q操作由於需要插入元素,所以我們需要將其轉化為能夠利用線段樹解決的問題。
這個序列是動態的,我們不妨將它變成靜態的。
模擬添數的過程,對於每次查詢,存下每次查詢的區間左右端點,對於每次插入,記下插入的數以及它所對應的前一次查詢的編號,便於後面找到上一次查詢的答案。
然後,對記下的插入的數字先建線段樹。
最後,循環枚舉每次詢問,在詢問中繼續枚舉它所對應的插入,更新每次插入的值,以線段樹單點修改的功能來實現。
看似先枚舉詢問,再枚舉插入,是兩重循環,但是由於在此循環中枚舉插入的j只增不減(詳見代碼),因此不會超時。

部分易錯點:
註意第0次詢問(即前面沒有詢問)的情況要單列。

代碼呈現:
(Luogu: Time: 712 MS; Memory: 12.05 MB; Code: 2.04 KB)
(BZOJ: Time: 1088 MS; Memory: 13324 KB; Code: 2333 B)
註: 由於不同OJ評測方式不盡相同,因此時間空間等結果有所差別,屬正常現象

?#include<cstdio>
#include<algorithm>
using namespace std;

const int MAXN = 2e5;
int MODN;
struct Node
{
    int left,right;
    int maxi;
};
struct SegmentTree
{
    Node nd[MAXN*4+2];
    
    void init()
    {
        for(int i=1; i<=MAXN*4; i++)
        {
            nd[i].left = nd[i].right = nd[i].maxi = 0;
        }
    }
    
    void build(int lbound,int rbound,int pos,int a[])
    {
        nd[pos].left = lbound;
        nd[pos].right = rbound;
        if(lbound==rbound)
        {
            nd[pos].maxi = a[lbound];
            return;
        }
        int mid = (lbound+rbound)/2;
        build(lbound,mid,2*pos,a);
        build(mid+1,rbound,2*pos+1,a);
        nd[pos].maxi = max(nd[2*pos].maxi,nd[2*pos+1].maxi);
    }
    
    void modify(int bound,int val,int pos)
    {
        int mid = (nd[pos].left+nd[pos].right)/2;
        if(nd[pos].left==nd[pos].right)
        {
            nd[pos].maxi = val;
            return;
        }
        if(bound<=mid) modify(bound,val,2*pos);
        else modify(bound,val,2*pos+1); 
        nd[pos].maxi = max(nd[2*pos].maxi,nd[2*pos+1].maxi);
    }
     
    int query(int lbound,int rbound,int pos)
    {
        int mid = (nd[pos].left+nd[pos].right)/2;
        if(lbound==nd[pos].left && rbound==nd[pos].right) return nd[pos].maxi;   
        int ans;
        if(rbound<=mid) ans = query(lbound,rbound,2*pos);
        else if(lbound>mid) ans = query(lbound,rbound,2*pos+1);
        else ans = max(query(lbound,mid,2*pos),query(mid+1,rbound,2*pos+1));
        return ans;
    }
};
SegmentTree st;
int a[MAXN+2];
int p[MAXN+2];
int ql[MAXN+2];
int qr[MAXN+2];
int n,m,q;

int main()
{
    char ch[5];
    int x;
    n = q = 0;
    scanf("%d%d",&m,&MODN);
    for(int i=1; i<=m; i++)
    {
        scanf("%s",ch);
        switch(ch[0])
        {
            case ‘A‘:
            {
                scanf("%d",&x);
                a[++n] = x;
                p[n] = q;
                break;
            }
            case ‘Q‘:
            {
                scanf("%d",&x);
                ql[++q] = n-x+1;
                qr[q] = n;
                break;
            }
        }
    }
    st.init();
    st.build(1,n,1,a);
    int j = 1;
    while(j<=n && !p[j])
    {
        j++;
    }
    for(int i=1; i<=q; i++)
    {
        int ans = st.query(ql[i],qr[i],1);
        printf("%d\n",ans);
        while(j<=n && p[j]==i)
        {
            st.modify(j,(int)((long long)a[j]+ans)%MODN,1);
            j++;
        }
    }
    
    return 0;
}?

Luogu P1198 BZOJ 1012 最大數 (線段樹)