【bzoj 3489】A simple rmq problem

傳送門~
作爲簡易的Kd tree 模板
將一個數作爲一個點(x,y,z)
x 爲該點位置,y 爲左面第一個和它一樣的數的位置,z 是右面第一個和他一樣的數的位置
問題轉化成,給定lr ,求一個權值最大的點,使
y<l
z>r
r=>x=>l
就成了在一個長方體中求一個最大的值
代碼:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<cstdlib>
using namespace std;
int num[200005],point[200005];
int pre[200005],nex[200005];
int cmpd,n,m,ans,lx,ly,root;
struct data{
    int d[3],mx[3],mn[3],val,maxn;
    int l,r;
}s[200005];
bool cmp(data r1,data r2){
    return r1.d[cmpd]<r2.d[cmpd];
}
void maintain(int now){
    int l=s[now].l,r=s[now].r;  
    for (int i=0;i<=2;i++){  
        if(l){s[now].mx[i]=max(s[now].mx[i],s[l].mx[i]);s[now].mn[i]=min(s[now].mn[i],s[l].mn[i]);}
        if(r){s[now].mx[i]=max(s[now].mx[i],s[r].mx[i]);s[now].mn[i]=min(s[now].mn[i],s[r].mn[i]);}        
    }  
    if(l) s[now].maxn=max(s[l].maxn,s[now].maxn);
    if(r) s[now].maxn=max(s[r].maxn,s[now].maxn);
}

int build(int l,int r,int d){
    if(l>r) return 0;
    d%=3;cmpd=d;
    int mid=l+r>>1;
    nth_element(s+l,s+mid,s+r+1,cmp);
    for(int i=0;i<=2;i++) s[mid].mx[i]=s[mid].mn[i]=s[mid].d[i];
    s[mid].l=build(l,mid-1,d+1);
    s[mid].r=build(mid+1,r,d+1);
    maintain(mid);
    return mid;
}
bool check(int now){
    if(s[now].mx[0]<lx || s[now].mn[0]>ly) return 0;
    if(s[now].mn[1]>=lx) return 0;
    if(s[now].mx[2]<=ly) return 0;  
    return 1;
}
void ch(int now){
    if(s[now].d[0]>=lx && s[now].d[0]<=ly && s[now].d[1]<lx && s[now].d[2]>ly) ans=max(ans,s[now].val);
    int l=s[now].l,r=s[now].r;
    if(l && s[l].maxn>ans && check(l)) ch(l);
    if(r && s[r].maxn>ans && check(r)) ch(r);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&num[i]);
    for(int i=1;i<=n;i++) {pre[i]=point[num[i]];point[num[i]]=i;}
    for(int i=1;i<=n;i++) point[i]=n+1;
    for(int i=n;i>=1;i--) {nex[i]=point[num[i]];point[num[i]]=i;}
    for(int i=1;i<=n;i++) {s[i].d[0]=i;s[i].d[1]=pre[i];s[i].d[2]=nex[i];s[i].val=num[i];s[i].maxn=num[i];}
    root=build(1,n,0);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&lx,&ly);
        lx=(lx+ans)%n+1;
        ly=(ly+ans)%n+1;
        if(lx>ly) swap(lx,ly);
        ans=0;ch(root);
        printf("%d\n",ans); 
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章