码迷,mamicode.com
首页 > 其他好文 > 详细

【bzoj3489】A simple rmq problem

时间:2018-07-15 17:43:53      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:turn   注意   amp   应该   com   线段   bool   为我   www.   

Portal -->bzoj3489

Solution

  最近计划智力康复qwq(话说这题一年前刚刚开始写树套树的时候感觉好难啊qwq现在看其实还好也算是有进步的嘛!)

  比较重要的一步是,要将“在\([l,r]\)中只出现一次”这个条件转化成"\(nxt[x]>r\)&&\(pre[x]<l\)",其中\(nxt[x]\)表示下一个出现位置\(x\)的数的位置,\(pre[x]\)表示前一个

  然后我们就发现其实是有三个限制:

1、\(pre[x]<l\)

2、\(nxt[x]>r\)

3、最大

  那所以我们用两棵主席树套在一起就好了

?  外层的主席树按照\(pre[x]\)来顺序加点,树内按照\(nxt\)的顺序为关键字,然后对于每个节点(也就是区间啦),再开一棵主席树,以\(nxt\)为根的顺序,树内以\(val[x]\)为关键字(也就是权值线段树啦)

?  然后修改直接修改,查询的时候我们先二分一下外层主席树应该调用哪个\(rt\),也就是二分一个最大的\(pos\)满足\(pre[pos]<l\),然后\(query(rt[pos],l,r)\)即可

  想清楚了的话还是比较好写的

  有一些需要稍微注意一下的小细节

1、如果说对于那些后面已经没有与其相同的数的位置,为了方便我们将其\(nxt\)赋成\(n+1\),所以这里要注意主席树的区间应该是\([1,n+1]\)

2、查询的时候,要注意因为我们要求的是\(nxt[x]>r\),所以在查询中涉及到的范围应该是\(>\)而不是\(>=\)之类的,跟平时写线段树有那么一点点小区别稍微注意一下

  

  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010,M=200010,SEG=N*20;
struct Data{
    int pre,nxt,id,val;
    friend bool operator < (Data x,Data y)
    {return x.pre<y.pre;}
}a[N];
int loc[N];
int n,m,ans;
namespace NodeSeg{/*{{{*/
    int ch[SEG*20][2],mx[SEG*20],rt[SEG];
    int n,tot;
    int newnode(int pre){
        ch[++tot][0]=ch[pre][0],ch[tot][1]=ch[pre][1]; mx[tot]=mx[pre];
        return tot;
    }
    void pushup(int x){mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]);}
    void _update(int pre,int &x,int lx,int rx,Data &delta){
        x=newnode(pre);
        if (lx==rx){mx[x]=delta.val;return;}
        int mid=lx+rx>>1;
        if (delta.id<=mid) _update(ch[pre][0],ch[x][0],lx,mid,delta);
        else _update(ch[pre][1],ch[x][1],mid+1,rx,delta);
        pushup(x);
    }
    void update(int pre,int x,Data delta){_update(rt[pre],rt[x],1,n,delta);}
    int _query(int x,int l,int r,int lx,int rx){
        if (mx[x]==0) return 0;
        if (l<=lx&&rx<=r) return mx[x];
        int mid=lx+rx>>1,ret=0;
        if (l<=mid) ret=max(ret,_query(ch[x][0],l,r,lx,mid));
        if (r>mid) ret=max(ret,_query(ch[x][1],l,r,mid+1,rx));
        return ret;
    }
    int query(int x,int l,int r){return _query(rt[x],l,r,1,n);}
}/*}}}*/
namespace NextSeg{/*{{{*/
    int ch[SEG][2],rt[SEG];
    int n,tot;
    int newnode(int pre,Data delta){
        ch[++tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1];
        NodeSeg::update(pre,tot,delta);
        return tot;
    }
    void _update(int pre,int &x,int lx,int rx,Data delta){
        x=newnode(pre,delta);
        if (lx==rx) return;
        int mid=lx+rx>>1;
        if (delta.nxt<=mid) _update(ch[pre][0],ch[x][0],lx,mid,delta);
        else _update(ch[pre][1],ch[x][1],mid+1,rx,delta);
    }
    void update(int x,Data delta){_update(rt[x-1],rt[x],1,n,delta);}
    int _query(int x,int l,int r,int lx,int rx){
        if (r<lx&&rx<=n) return NodeSeg::query(x,l,r);
        int mid=lx+rx>>1,ret=0;
        if (r<mid) ret=max(ret,_query(ch[x][0],l,r,lx,mid));
        ret=max(ret,_query(ch[x][1],l,r,mid+1,rx));
        return ret;
    }
    int query(int x,int l,int r){return _query(rt[x],l,r,1,n);}
}/*}}}*/
int read(){
    int ret=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while ('0'<=ch&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    return ret;
}

void prework(){
    for (int i=1;i<=n;++i) a[i].pre=0,a[i].nxt=n+1;
    for (int i=1;i<=n;++i){
        a[i].id=i;
        if (loc[a[i].val]) 
            a[loc[a[i].val]].nxt=i,a[i].pre=loc[a[i].val];
        loc[a[i].val]=i;
    }
    NodeSeg::n=n+1; NextSeg::n=n+1;
}

int get_pos(int x){
    int l=1,r=n,mid,ret=l;
    while (l<=r){
        mid=l+r>>1;
        if (x<=a[mid].pre) r=mid-1;
        else l=mid+1;
    }
    return l-1;
}

int main(){/*{{{*/
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    int x,y,x1,y1,pos;
    n=read(); m=read();
    for (int i=1;i<=n;++i) a[i].val=read();
    prework();
    sort(a+1,a+1+n);
    for (int i=1;i<=n;++i)
        NextSeg::update(i,a[i]);
    for (int i=1;i<=m;++i){
        x1=read(); y1=read();
        x=min((x1+ans)%n+1,(y1+ans)%n+1);
        y=max((x1+ans)%n+1,(y1+ans)%n+1);
        pos=get_pos(x);
        ans=NextSeg::query(pos,x,y);
        printf("%d\n",ans);
    }
}/*}}}*/

【bzoj3489】A simple rmq problem

标签:turn   注意   amp   应该   com   线段   bool   为我   www.   

原文地址:https://www.cnblogs.com/yoyoball/p/9313850.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!