题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5919
题意: 给一个区间,经过运算后会得到一个区间。然后问这个区间里面有几个个不同的数,假设不同的数有n个,
然后将这个区间不同的数进行排序,输出第n/2个的在区间第一次出现的下标就可以了。
思路:我这是主席树专题里的,肯定要往主席树想,题目要的是第一次出现的位置,所以可以从后往前建树。
然后按照每个位置的下标进行维护,再来个数组避免重复就可以了,数组记得要开大点
#include<iostream> #include<cmath> #include<stdio.h> #include<algorithm> #include<cstring> #include<map> #include<vector> using namespace std; int a[8000010]; int root[2000010],lson[8000010],rson[8000010]; int sum[8000010],top,fa[2000010]; void init() { top = 0; memset(sum,0,sizeof(sum)); memset(root,0,sizeof(root)); memset(lson,0,sizeof(lson)); memset(rson,0,sizeof(rson)); for(int i=0;i<2000010;i++) fa[i]=-1; } void Update(int l,int r,int &now,int last,int pos,int x) { now=++top; lson[now]=lson[last]; rson[now]=rson[last]; sum[now]=sum[last]+x; if(l==r) return; int mid=(l+r)>>1; if(pos<=mid) Update(l,mid,lson[now],lson[last],pos,x); else Update(mid+1,r,rson[now],rson[last],pos,x); } int Query(int rt,int L,int R,int l,int r) { if(l<=L&&r>=R) return sum[rt]; int mid=(L+R)>>1; int ans=0; if(l<=mid) ans+=Query(lson[rt],L,mid,l,r); if(r>mid) ans+=Query(rson[rt],mid+1,R,l,r); return ans; } int getpos(int rt,int l,int r,int k) { if(l==r) return l; int ans=sum[lson[rt]]; int mid=(l+r)>>1; if(ans>=k) return getpos(lson[rt],l,mid,k); else return getpos(rson[rt],mid+1,r,k-ans); } int main() { int T,n,m; scanf("%d",&T); int u=0; while(T--) { init(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=n;i>=1;i--) { if(fa[a[i]]==-1) Update(1,n,root[i],root[i+1],i,1); else { Update(1,n,root[i],root[i+1],fa[a[i]],-1); Update(1,n,root[i],root[i],i,1); } fa[a[i]] = i; } int ans = 0; printf("Case #%d:",++u); while(m--) { int l,r; scanf("%d%d",&l,&r); l = (l + ans) % n + 1; r = (r + ans) % n + 1; if(l > r) swap(l,r); int k=(Query(root[l],1,n,l,r)+1)>>1; printf(" %d",ans=getpos(root[l],1,n,k)); } printf(" "); } return 0; }