[主席树] Codeforces 840D .Destiny

来源:互联网 发布:淘宝代理货源平台 编辑:程序博客网 时间:2024/05/16 03:05

%%%Vectorxj
设答案为p=rl+1k,如果把区间元素排序,那么答案一定是第p个、第2p个…第kp个元素中的一个。
因为答案出现次数大于p,一定会跨越一个边界,所以以上结论成立
那么就在主席树上二分出这些数,找出最小的满足条件的就可以了

#include <cstdio>#include <iostream>#include <algorithm>#include <vector>using namespace std;const int N=300010;int n,m,cnt;int a[N],rt[N],tot[N*80],ls[N*80],rs[N*80];void Build(int &g,int l,int r){    g=++cnt; tot[g]=0;    if(l==r) return ;    int mid=l+r>>1;    Build(ls[g],l,mid); Build(rs[g],mid+1,r);}void Add(int &g1,int g2,int x,int l,int r){    g1=++cnt; ls[g1]=ls[g2]; rs[g1]=rs[g2]; tot[g1]=tot[g2]+1;    if(l==r) return ;    int mid=l+r>>1;    if(x<=mid) Add(ls[g1],ls[g2],x,l,mid);    else Add(rs[g1],rs[g2],x,mid+1,r);}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) scanf("%d",&a[i]);    Build(rt[0],1,n);    for(int i=1;i<=n;i++)        rt[i]=rt[i-1],Add(rt[i],rt[i],a[i],1,n);    while(m--){        int l,r,k,ans=-1;        scanf("%d%d%d",&l,&r,&k);        int cur=(r-l+1)/k;        if(cur==0){            int L=1,R=n,g1=rt[r],g2=rt[l-1];            while(L<R){                int mid=L+R>>1;                if(tot[ls[g1]]-tot[ls[g2]]>0)                    g1=ls[g1],g2=ls[g2],R=mid;                else                    g1=rs[g1],g2=rs[g2],L=mid+1;            }            printf("%d\n",L);            continue;        }        for(int i=cur;i<=r-l+1;i+=cur){            int L=1,R=n,g1=rt[r],g2=rt[l-1],now=i;            while(L<R){                int mid=L+R>>1;                if(tot[ls[g1]]-tot[ls[g2]]>=now)                    g1=ls[g1],g2=ls[g2],R=mid;                else                    L=mid+1,now-=tot[ls[g1]]-tot[ls[g2]],g1=rs[g1],g2=rs[g2];            }            if((tot[g1]-tot[g2])*k>r-l+1 && (L<ans || ans==-1)) ans=L;        }        printf("%d\n",ans);    }    return 0;}
原创粉丝点击