赞
踩
给一个长度为n的序列a。1≤a[i]≤n。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。
依旧是权值线段树+可持久化的组合。也算主席树模板题吧,权当练手。
因为一个区间只有一个数的次数大于(r-l+1)/2,所以相当于单点查询
#define mid (l+r>>1) const int maxn=1e5+7; int n,m,a[maxn]; int tot=0,rt[maxn]; struct node{ int l,r,num; }t[maxn<<5]; void update(int &i,int l,int r,int pre,int x){ i=++tot; t[i]=t[pre]; t[i].num++; if(l==r) return; if(x<=mid) update(t[i].l,l,mid,t[pre].l,x); else update(t[i].r,mid+1,r,t[pre].r,x); } int query(int i,int l,int r,int pre,int k){ if(l==r) return l; if(t[t[i].l].num-t[t[pre].l].num>k) return query(t[i].l,l,mid,t[pre].l,k); if(t[t[i].r].num-t[t[pre].r].num>k) return query(t[i].r,mid+1,r,t[pre].r,k); return 0; } int main(){ n=read(); m=read(); for(int i=1;i<=n;i++){ a[i]=read(); update(rt[i],1,n,rt[i-1],a[i]); } for(int i=1;i<=m;i++){ int x,y; x=read(); y=read(); printf("%d\n",query(rt[y],1,n,rt[x-1],(y-x+1)/2)); } } /* Input 7 5 1 1 3 2 3 4 3 1 3 1 4 3 7 1 7 6 6 Output 1 0 3 0 4 */
题意:
给你n(n≤2∗10 ^ 5)个数,每个数的大小0<Ai≤2∗10 ^ 5。再给你m(m≤2∗10 ^ 5)个询问。对于每个询问输入l,r,表示Al…Ar这个区间我们得到每个数第一次出现的位置下标的排列,假设这个区间有k个不同的数,我们得到的排列是p1<p2<p3<…<pk,叫你求第(k+1)/2这个数是多少?
题解:
主席树模板题的变式,很容易想到其实就是找该区间中有多少种数的变形。
回顾一下这题的主席树做法:
给你 n 个数,然后有 q 个询问,每个询问会给你[l,r],输出[l,r]之间有多少种数字。
对于第i课主席树,区间以i为右端点,记录每个数字最后一次出现的位置,在那些位置+1.
更新时,如果这个元素之前出现过,就把之前记录的位置储存的信息 -1,然后在新的位置储存的信息 +1
查询[l,r],找第r课主席树,查询区间[l,n]。
第i个询问区间依赖于第i-1个询问的答案,所以是强制在线的。
因为要找每个数在该区间中第一次出现的位置,所以有个技巧是倒着插入主席树,每插入一个值,将当前数位置的贡献值+1,将之前已经出现过的该数的位置上的贡献值-1即可
#define mid (l+r>>1) const int maxn=2e5+7; int T,n,m,rt[maxn],a[maxn],tot,p[maxn],mp[maxn]; struct node{ int l,r,sum; }t[maxn*50]; void update(int &i,int l,int r,int pre,int x,int v){ i=++tot; t[i]=t[pre]; t[i].sum+=v; if(l==r) return; if(x<=mid) update(t[i].l,l,mid,t[pre].l,x,v); else update(t[i].r,mid+1,r,t[pre].r,x,v); } int query(int i,int l,int r,int x,int y){ if(l>y||r<x) return 0; if(x<=l&&r<=y) return t[i].sum; return query(t[i].l,l,mid,x,y)+query(t[i].r,mid+1,r,x,y); } int cc(int i,int l,int r,int k){ if(l==r) return l; if(t[t[i].l].sum>=k) return cc(t[i].l,l,mid,k); return cc(t[i].r,mid+1,r,k-t[t[i].l].sum); } void init(){ tot=0; memset(rt,0,sizeof(rt)); memset(mp,0,sizeof(mp)); } int main(){ T=read(); for(int v=1;v<=T;v++){ n=read(); m=read(); init(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=n;i;i--){ update(rt[i],1,n,rt[i+1],i,1); if(mp[a[i]]) update(rt[i],1,n,rt[i],mp[a[i]],-1); mp[a[i]]=i; } int temp=0; for(int i=1;i<=m;i++){ int x,y; x=read(); y=read(); x=(x+temp)%n+1; y=(y+temp)%n+1; if(x>y) swap(x,y); int ans=query(rt[x],1,n,x,y); ans=(ans+1)/2; p[i]=temp=cc(rt[x],1,n,ans); } printf("Case #%d:",v); for(int i=1;i<=m;i++) printf(" %d",p[i]); putchar('\n'); } } /* Input 2 5 2 3 3 1 5 4 2 2 4 4 5 2 2 5 2 1 2 2 3 2 4 Output Case #1: 3 3 Case #2: 3 1 */
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。