1. 程式人生 > >BZOJ3489:A simple rmq Problem

BZOJ3489:A simple rmq Problem

淺談主席樹:https://www.cnblogs.com/AKMer/p/9956734.html

題目傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=3489

題目意思就是線上求\(pos\)\([l,r]\)\(lst\)\([0,l-1]\)\(nxt\)\([r+1,n+1]\)的點中權值最大的。其中\(pos\)表示這個點的下標,\(lst\)表示上一個跟這個點相同的點的下標,\(nxt\)表示下一個跟這個點相同的點的下標。

這樣子就變成求立方體最大點值了,我們可以果斷樹套樹套樹走一波,然後獲得\(TLE\)的好成績。

所以我們得用一些神奇的手段

降低問題的維度。

而這個手段就是可持久化。

我們按\(lst\)從小到大在\(nxt\)值域範圍內建立可持久化線段樹,內套位置線段樹維護區間最大值即可。

時間複雜度:\(O(nlog^2n)\)

空間複雜度:\(O(nlog^2n)\)

程式碼如下:

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

const int maxn=1e5+5;

int n,m,lstans;
int rt[maxn],tmp[maxn];
int pos[maxn],a[maxn],lst[maxn],nxt[maxn];

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

struct Project {
    int lst,nxt,pos,val;

    Project() {}

    Project(int _lst,int _nxt,int _pos,int _val) {
        lst=_lst,nxt=_nxt,pos=_pos,val=_val;
    }

    bool operator<(const Project &a)const {
        return lst<a.lst;
    }
}p[maxn];

struct pos_chairman_tree {
    int tot;
    struct tree_node {
        int ls,rs,mx;
    }tree[maxn*18*18];

    void change(int &p,int lst,int l,int r,Project node) {
        p=++tot;tree[p]=tree[lst];
        tree[p].mx=max(tree[p].mx,node.val);
        if(l==r)return;
        int mid=(l+r)>>1;
        if(node.pos<=mid)change(tree[p].ls,tree[lst].ls,l,mid,node);
        else change(tree[p].rs,tree[lst].rs,mid+1,r,node);
    }

    int query(int p,int l,int r,int L,int R) {
        if(L<=l&&r<=R)return tree[p].mx;
        int mid=(l+r)>>1,res=0;
        if(L<=mid)res=max(res,query(tree[p].ls,l,mid,L,R));
        if(R>mid)res=max(res,query(tree[p].rs,mid+1,r,L,R));
        return res;
    }
}T2;

struct lst_chairman_tree {
    int tot;
    struct tree_node {
        int ls,rs,rt;
    }tree[maxn*18];

    void change(int &p,int lst,int l,int r,Project node) {
        p=++tot;tree[p]=tree[lst];
        T2.change(tree[p].rt,tree[lst].rt,1,n,node);
        if(l==r)return;
        int mid=(l+r)>>1;
        if(node.nxt<=mid)change(tree[p].ls,tree[lst].ls,l,mid,node);
        else change(tree[p].rs,tree[lst].rs,mid+1,r,node);
    }

    int query(int p,int l,int r,int L,int R) {
        if(!p)return 0;
        if(l>R)return T2.query(tree[p].rt,1,n,L,R);
        int mid=(l+r)>>1,res=query(tree[p].rs,mid+1,r,L,R);
        if(R+1<=mid)res=max(res,query(tree[p].ls,l,mid,L,R));
        return res;
    }
}T1;

int main() {
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        a[i]=read(),lst[i]=pos[a[i]],pos[a[i]]=i;
    for(int i=1;i<=n;i++)pos[i]=n+1;
    for(int i=n;i;i--)nxt[i]=pos[a[i]],pos[a[i]]=i;
    for(int i=1;i<=n;i++)p[i]=Project(lst[i],nxt[i],i,a[i]);
    sort(p+1,p+n+1);
    for(int i=1;i<=n;i++) {
        tmp[i]=p[i].lst;
        T1.change(rt[i],rt[i-1],2,n+1,p[i]);
    }
    for(int i=1;i<=m;i++) {
        int l=(read()+lstans)%n+1,r=(read()+lstans)%n+1;
        if(r<l)swap(l,r);
        int pos=lower_bound(tmp+1,tmp+n+1,l)-tmp-1;
        lstans=T1.query(rt[pos],2,n+1,l,r);
        printf("%d\n",lstans);
    }
    return 0;
}