zoukankan      html  css  js  c++  java
  • BZOJ3489 A simple rmq problem 【可持久化树套树】*

    BZOJ3489 A simple rmq problem


    Description

    因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。

    Input

    第一行为两个整数N,M。M是询问数,N是序列的长度(N<=100000,M<=200000)
    第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N
    再下面M行,每行两个整数x,y,
    询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<):
    l=min((x+lastans)mod n+1,(y+lastans)mod n+1);
    r=max((x+lastans)mod n+1,(y+lastans)mod n+1);
    Lastans表示上一个询问的答案,一开始lastans为0

    Output

    一共M行,每行给出每个询问的答案。

    Sample Input

    10 10
    6 4 9 10 9 10 9 4 10 4
    3 8
    10 1
    3 4
    9 4
    8 1
    7 8
    2 9
    1 1
    7 3
    9 9

    Sample Output

    4
    10
    10
    0
    0
    10
    0
    4
    0
    4


    还是吐槽一下BZOJ的土豆(评测机),什么数组开小了显示WA,数组开大一点就CE,这可真是友好,请问RE呢?MLE呢?????????


    然后讲讲这题思路
    一开始看到以为是树套树套树
    蒙圈了
    想了⑩分钟无果然后就去看题解
    结果发现可以用排序的方法把三维降成两维

    只不过嘛。需要可持久化
    不过我们不虚
    可持久化树套树不就是在可持久化线段树上多加一句插入吗理直气壮
    首先我们考虑一个数在区间内出现一次的充要条件是什么
    1.l<=posi<=r
    2.l>prei
    3.r<nxti
    其中pos表示位置,pre和nxt分别表示上一个和下一个这个数出现的位置
    很妙啊
    我们考虑以pre为键值排序
    然后我们发现我们查询的区间变成了一个前缀
    所以就将pre可持久化一下
    然后我们又发现nxt也是我们的限制条件
    所以我们在外层的树上以nxt为下标,所以查询就变成了在线段树上查询后缀

    但是还有pos的限制怎么办?
    所以就把内层树搞成原序列的位置就好了
    然后查询的时候非常套路地二分一下pre的位置,剩下的该怎么查怎么查


    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        int ans=0,w=1;char c=getchar();
        while(!isdigit(c)&&c!='-')c=getchar();
        if(c=='-')w=-1,c=getchar();
        while(isdigit(c))ans=(ans<<1)+(ans<<3)+c-'0',c=getchar();
        return ans*w;
    }
    #define N 100010
    int n,m,lastans=0;
    struct Node{int val,pos,pre,nxt;}p[N];
    bool cmp(Node a,Node b){return a.pre<b.pre;}
    //inside 原序列顺序
    int ld[N*350],rd[N*350],maxv[N*350];
    int cnt=0;
    void insert(int &t,int last,int l,int r,int pos,int vl){
        t=++cnt;
        maxv[t]=max(vl,maxv[last]);
        if(l==r)return;
        ld[t]=ld[last];
        rd[t]=rd[last];
        int mid=(l+r)>>1;
        if(pos<=mid)insert(ld[t],ld[last],l,mid,pos,vl);
        else insert(rd[t],rd[last],mid+1,r,pos,vl);
    }
    int query(int t,int l,int r,int L,int R){
        if(!t)return 0;
        if(L<=l&&r<=R)return maxv[t];
        int mid=(l+r)>>1;
        if(R<=mid)return query(ld[t],l,mid,L,R);
        if(L>mid)return query(rd[t],mid+1,r,L,R);
        return max(query(ld[t],l,mid,L,R),query(rd[t],mid+1,r,L,R));
    }
    //outside nxt顺序
    int rt[N*20],lc[N*20],rc[N*20],tot=0;
    void insert(int &t,int last,int l,int r,int key,int pos,int vl){
        t=++tot;
        insert(rt[t],rt[last],1,n,pos,vl);
        if(l==r)return;
        lc[t]=lc[last];
        rc[t]=rc[last];
        int mid=(l+r)>>1;
        if(key<=mid)insert(lc[t],lc[last],l,mid,key,pos,vl);
        else insert(rc[t],rc[last],mid+1,r,key,pos,vl);
    }
    int query(int t,int l,int r,int L,int R,int ql,int qr){
        if(!t)return 0;
        if(L<=l&&r<=R)return query(rt[t],1,n,ql,qr);
        int mid=(l+r)>>1;
        if(R<=mid)return query(lc[t],l,mid,L,R,ql,qr);
        if(L>mid)return query(rc[t],mid+1,r,L,R,ql,qr);
        return max(query(lc[t],l,mid,L,R,ql,qr),query(rc[t],mid+1,r,L,R,ql,qr));
    }
    int outrt[N];
    int pre[N],nxt[N];
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)p[i].pos=i,scanf("%d",&p[i].val);
        for(int i=1;i<=n;i++)pre[i]=0,nxt[i]=n+1;
        for(int i=1;i<=n;i++)p[i].pre=pre[p[i].val],pre[p[i].val]=i;
        for(int i=n;i>=1;i--)p[i].nxt=nxt[p[i].val],nxt[p[i].val]=i;
        //for(int i=1;i<=1000;i++)cout<<i<<" "<<p[i].pre<<" "<<p[i].nxt<<endl;
        sort(p+1,p+n+1,cmp);
        for(int i=1;i<=n;i++)//持久化pre的顺序
            insert(outrt[i],outrt[i-1],1,n+1,p[i].nxt,p[i].pos,p[i].val);
        for(int i=1;i<=m;i++){
            int l,r;
            scanf("%d%d",&l,&r);
            l=(l+lastans)%n+1;
            r=(r+lastans)%n+1;
            if(l>r)swap(l,r);
            int ql=1,qr=n,tmp=0;
            while(ql<=qr){
                int mid=(ql+qr)>>1;
                if(p[mid].pre<l)ql=mid+1,tmp=mid;
                else qr=mid-1;
            }
            printf("%d
    ",lastans=query(outrt[tmp],1,n+1,r+1,n+1,l,r));
        }
        return 0;
    }
  • 相关阅读:
    declare handler 声明异常处理的语法
    mysql存储过程获取sqlstate message_text
    mongoTemplate操作内嵌文档
    mysql索引之七:组合索引中选择合适的索引列顺序
    mongoDB的操作总结
    explain之三:MYSQL EXPLAIN语句的extended 选项学习体会,分析诊断工具之二
    状态模式
    代码重构----使用java有限状态机来消除太多的if else判断
    断路器(CircuitBreaker)设计模式
    断路器之一:Hystrix 使用与分析
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676288.html
Copyright © 2011-2022 走看看