• HDU


     HDU - 5919 

    题意:n个数,m个询问,每次询问区间[l,r],设[l,r]内不同的数有k个,它们在该区间第一个次出现的位置是p1,p2...pk(p1<p2<pk),回答p(k+1)/2.

    思路:主席树查区间不同的数的个数这个就不说了,前面的博客有提到过。问题就在于我们在知道k之后,找p(k+1)/2,难道需要在重新建一棵以权值线段树建的主席树,或者二分去找?

    其实并不用,在前面博客查区间不同的数的时候我们是从左往右建的,这样的话,主席树中,相同的数都是保存在当前出现过的最右位置。那反过来,从右往左建的话,相同的数就是保存在当前出现过的最左位置,然后再在这方面找第(k+1)/2大的数即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+11;
    struct Tree{
        int lson,rson,val;
    }T[N*32];
    int tn,a[N],root[N],vis[N];
    int build(int l,int r){
        int cur=++tn,mid=(l+r)>>1;
        T[cur].val=0;
        T[cur].lson=T[cur].rson=0;
        if(l==r) return cur;
        T[cur].lson=build(l,mid);
        T[cur].rson=build(mid+1,r);
        return cur;
    }
    int addT(int x,int l,int r,int p,int val){
        int cur=++tn,mid=(l+r)>>1;
        T[cur]=T[x];
        T[cur].val=T[x].val+val;
        if(l==r) return cur;
        if(p<=mid) T[cur].lson=addT(T[x].lson,l,mid,p,val);
        else T[cur].rson=addT(T[x].rson,mid+1,r,p,val);
        return cur;
    }
    int query(int x,int l,int r,int qr){
        if(r<=qr) return T[x].val;
        int ans=0,mid=(l+r)>>1;
        ans+=query(T[x].lson,l,mid,qr);
        if(qr>mid) ans+=query(T[x].rson,mid+1,r,qr);
        return ans;
    }
    int findk(int x,int l,int r,int k){
        if(l==r) return l;
        int mid=(l+r)>>1;
        int lval=T[T[x].lson].val;
        if(lval>=k) return findk(T[x].lson,l,mid,k);
        else return findk(T[x].rson,mid+1,r,k-lval); 
    } 
    int main(){
        int t=1,T;
        scanf("%d",&T);
        while(T--){
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
                vis[a[i]]=0;
            }
            tn=0;
            root[n+1]=build(1,n);
            for(int i=n;i>=0;i--){
                int tempr=root[i+1];
                if(vis[a[i]]) tempr=addT(tempr,1,n,vis[a[i]],-1);
                root[i]=addT(tempr,1,n,i,1);
                vis[a[i]]=i;
            }
            int l,r,ans=0;
            printf("Case #%d:",t++);
            while(m--){
                scanf("%d%d",&l,&r);
                l=(l+ans)%n+1;r=(r+ans)%n+1;
                if(l>r) swap(l,r);
                int pos=query(root[l],1,n,r);
                pos=(pos+1)/2;
                ans=findk(root[l],1,n,pos);
                printf(" %d",ans);
            }
            printf("
    ");
        }
        return 0;
    }
    主席树下主席果
  • 相关阅读:
    linux基础——虚拟机的创建及安装操作系统
    并发编程之多进程
    操作系统与进程(理论知识点)
    粘包
    socket-网络编程
    网络编程1
    网络编程
    异常
    元类
    反射与内置方法
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/13270156.html
Copyright © 2020-2023  润新知