题目链接:hdu_5919_Sequence II
题意:
给你n个数,m个询问,每次问你一个区间中每一种数在区间中第一次出现的位置的中位数,强制在线。
题解:
一看就是主席树搞,不过这里要询问第一次出现的位置,有个技巧就是倒着将数插进去,如果有相同的数,就把位置靠后的数的贡献取消掉,这样查询的时候就只需要查询root[l]了,因为root[l]包括了l到n的信息,前面已经只保留了相同数的最前面的位置,所以查询一共有多少种数时直接查询root[l]的l到r就行了。
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 5 const int N=2e5+7; 6 struct node{int l,r,sum;}T[40*N]; 7 8 int t,n,m,a[N],pre[N],root[N],tot,ic=1; 9 10 void update(int &x,int y,int pos,int val,int l=1,int r=n) 11 { 12 T[++tot]=x?T[x]:T[y],T[tot].sum+=val,x=tot; 13 if(l==r)return; 14 int m=l+r>>1; 15 if(pos<=m)update(T[x].l,T[y].l,pos,val,l,m); 16 else update(T[x].r,T[y].r,pos,val,m+1,r); 17 } 18 19 int query(int x,int k,int l=1,int r=n) 20 { 21 if(l==r)return l; 22 int m=l+r>>1; 23 if(k<=T[T[x].l].sum)return query(T[x].l,k,l,m); 24 return query(T[x].r,k-T[T[x].l].sum,m+1,r); 25 } 26 27 int getsum(int x,int L,int R,int l=1,int r=n) 28 { 29 if(L<=l&&r<=R)return T[x].sum; 30 int m=l+r>>1,ans=0; 31 if(L<=m)ans+=getsum(T[x].l,L,R,l,m); 32 if(R>m)ans+=getsum(T[x].r,L,R,m+1,r); 33 return ans; 34 } 35 36 int main() 37 { 38 scanf("%d",&t); 39 while(t--) 40 { 41 printf("Case #%d: ",ic++); 42 scanf("%d%d",&n,&m); 43 tot=0; 44 F(i,1,n)scanf("%d",a+i); 45 for(int i=n;i>0;i--) 46 { 47 if(pre[a[i]])update(root[i],root[i+1],pre[a[i]],-1); 48 update(root[i],root[i+1],i,1); 49 pre[a[i]]=i; 50 } 51 int ans=0,l,r,sum; 52 F(i,1,m) 53 { 54 scanf("%d%d",&l,&r); 55 l=(l+ans)%n+1,r=(r+ans)%n+1; 56 if(l>r)l^=r,r^=l,l^=r; 57 sum=getsum(root[l],l,r); 58 printf("%d%c",ans=query(root[l],sum+1>>1)," \n"[i==m]); 59 } 60 while(tot)T[tot].l=T[tot].r=T[tot].sum=0,tot--; 61 F(i,1,n)root[i]=0,pre[a[i]]=0; 62 } 63 return 0; 64 }
时间: 2024-11-04 22:39:03