• 主席树——求区间第k个不同的数字(向右密集hdu5919)


    和向左密集比起来向右密集只需要进行小小的额修改,就是更新的时候从右往左更新。。

    自己写的被卡死时间。不知道怎么回事,和网上博客的没啥区别。。

    /*
    给定一个n个数的序列a
    每次询问区间[l,r],求出去重后区间中每个数的第一次出现的位置pi
    pi构成一个新的升序,求这个新数组的中位数
    
    要求强制在线,询问[l,r]根据上一个询问的答案进行加密,形成新的询问
    t1=(l+ansi-1) % mod n + 1
    t2=(r+ansi-1) % mod n + 1 
    l=min(t1,t2),r=max(t1,t2)
    然后再进行询问即可 
    
    先求出a[i]在序列中上一次出现的位置pre[i] 
    从左往右进行一次扫描,用主席树来维护区间[1,i]的中不同数字的个数
    询问[l,r]:
    先求出区间出现的不同数字的个数k,具体操作见SPOJ D-QUERY 
    要求从左往右第k/2个数,很容易想到二分,在第r棵线段树上询问[mid,r]区间不同数字出现的个数,这样的复杂度是O(q*(logn)^2) 
    但这种做法是错的。。
    出现这种情况是因为我们所有版本的线段树的点都是向后密集的,第i个棵线段树维护a[i]及之前的数最后出现的位置 
    
    所以只要每个版本的线段树中不同的数出现的位置能够向前密集,那么这个问题就转变成了求第k大的数
    考虑如何将数据向前密集,即保存a[i]下一次出现的位置,扫到a[i]时将i+1,将下一次出现的位置-1即可
    update:a[i]
        所以从右往左更新主席树,nxt[i]-1,i+1 
    query:[l,r]
        先在第l个版本的线段树上查询[1,r]区间的不同数字的个数l 
        在第l个版本的线段树上查询[1,r]范围内的第k/2大数的下标 
        
    可以发现这种主席树的查询其实退化成了线段树 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 200005
    #define INF 0x3f3f3f3f 
    struct Node{int lc,rc,sum;}t[maxn*25];
    int n,a[maxn],rt[maxn],size,nxt[maxn],pos[maxn];
    int build(int l,int r){
        int now=++size;
        t[now].lc=t[now].rc=t[now].sum=0;
        if(l==r)return now;
        int mid=l+r>>1;
        t[now].lc=build(l,mid);
        t[now].rc=build(mid+1,r);
        return now;
    } 
    int update(int last,int pos,int val,int l,int r){
        int now=++size;
        t[now]=t[last];t[now].sum+=val;
        if(l==r)return now;
        int mid=l+r>>1;
        if(pos<=mid)t[now].lc=update(t[last].lc,pos,val,l,mid);
        else t[now].rc=update(t[last].rc,pos,val,mid+1,r);
        return now;
    }
    int query1(int rt,int L,int R,int l,int r){//查询区间[L,R]的和 
        if(L<=l && R>=r)return t[rt].sum;
        int mid=l+r>>1,res=0;
        if(L<=mid) res+=query1(t[rt].lc,L,R,l,mid);
        if(R>mid)res+=query1(t[rt].rc,L,R,mid+1,r);
        return res;
    }
    int query2(int rt,int k,int l,int r){//查询线段树第k大的值 
        if(l==r)return l;
        int mid=l+r>>1;
        if(k<=t[t[rt].lc].sum)return query2(t[rt].lc,k,l,mid); 
        else return query2(t[rt].rc,k-t[t[rt].lc].sum,mid+1,r);
    }
    
    int main(){
        int T,q;cin>>T;
        for(int tt=1;tt<=T;tt++){
            size=0;memset(rt,0,sizeof rt);
            memset(nxt,0x3f,sizeof nxt);
            memset(pos,0x3f,sizeof pos);
            
            scanf("%d%d",&n,&q);
            for(int i=1;i<=n;i++)scanf("%d",&a[i]);
            for(int i=n;i>=1;i--){
                nxt[i]=pos[a[i]];
                pos[a[i]]=i; 
            }
            rt[n+1]=build(1,n);
            for(int i=n;i>=1;i--){
                if(nxt[i]==INF)rt[i]=update(rt[i+1],i,1,1,n);//直接在点i增加1
                else {
                    int tmp=update(rt[i+1],nxt[i],-1,1,n);
                    rt[i]=update(tmp,i,1,1,n);
                } 
            }
            
            printf("Case #%d:",tt);
            int ans=0,l,r;
            while(q--){
                scanf("%d%d",&l,&r);
                int t1=(l+ans)%n+1,t2=(r+ans)%n+1;
                l=min(t1,t2),r=max(t1,t2);
                int k=query1(rt[l],1,r,1,n);
                ans=query2(rt[l],k/2+k%2,1,n);//求第k个数的下标 
                printf(" %d",ans);
            }
            puts("");
        }
    }

     下面的是ac的。。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 222222
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int tot,rt[MAX];
    struct Node
    {
        int ls,rs;
        int v;
    }t[MAX<<5];
    void Modify(int &x,int ff,int l,int r,int p,int w)
    {
        t[x=++tot]=t[ff];t[x].v+=w;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(p<=mid)Modify(t[x].ls,t[ff].ls,l,mid,p,w);
        else Modify(t[x].rs,t[ff].rs,mid+1,r,p,w);
    }
    int Query(int r1,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R)return t[r1].v;
        int mid=(l+r)>>1,ret=0;
        if(L<=mid)ret+=Query(t[r1].ls,l,mid,L,R);
        if(R>mid)ret+=Query(t[r1].rs,mid+1,r,L,R);
        return ret;
    }
    int Kth(int r1,int l,int r,int K)
    {
        if(l==r)return l;
        int mid=(l+r)>>1,s=t[t[r1].ls].v;
        if(s>=K)return Kth(t[r1].ls,l,mid,K);
        else return Kth(t[r1].rs,mid+1,r,K-s);
    }
    int ans,n,a[MAX],m;
    int lst[MAX],pos[MAX];
    int main()
    {
        int T=read();
        for(int TTT=1;TTT<=T;++TTT)
        {
            printf("Case #%d:",TTT);
            memset(rt,0,sizeof(rt));
            memset(t,0,sizeof(t));
            memset(lst,0,sizeof(lst));
            memset(pos,0,sizeof(pos));
            tot=ans=0;
            n=read();m=read();
            for(int i=1;i<=n;++i)a[i]=read();
            for(int i=n;i;--i)
                if(!pos[a[i]])Modify(rt[i],rt[i+1],1,n,i,1),pos[a[i]]=i;
                else
                {
                    Modify(rt[i],rt[i+1],1,n,i,1);
                    Modify(rt[i],rt[i],1,n,pos[a[i]],-1);
                    pos[a[i]]=i;
                }
            while(m--)
            {
                int L=(read()+ans)%n+1,R=(read()+ans)%n+1;
                if(L>R)swap(L,R);
                int S=Query(rt[L],1,n,L,R);
                ans=Kth(rt[L],1,n,(S+1)/2);
                printf(" %d",ans);
            }
            puts("");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    表现层(jsp)、持久层(类似dao)、业务层(逻辑层、service层)、模型(javabean)、控制层(action)
    理解HTTP session原理及应用
    “不同浏览器对于同一域名的并发获取(加载)资源数是有限的”
    URL编码与解码
    URL和URI的区别与联系
    spring 源代码地址
    java_ant详解
    Struts2 Convention插件的使用
    Struts2的@ResultPath
    Java Annotation原理分析(一)
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10751843.html
Copyright © 2020-2023  润新知