1. 程式人生 > >hdu5919 Sequence II(主席樹)

hdu5919 Sequence II(主席樹)

題目連結:

題意:

給你n(n2105)個數,每個數的大小0<Ai2105。再給你m(m2105)個詢問。對於每個詢問輸入l,r,表示Al...Ar這個區間我們得到每個數第一次出現的位置下標的排列,假設這個區間有k個不同的數,我們得到的排列是p1<p2<p3<...<pk,叫你求第(k+1)/2這個數是多少?

題解:

1、我們利用主席樹記錄相同的數的前一個位置是多少,很容易得到區間有多少個不同的數,但是我們要得到第(k+1)/2這個數的話我們要二分去求解。時間複雜度為O(nlog2(n)),,在hdu會超時。

2、如果我們從後往前的話在當前位置i

我們在主席樹上i這個位置加1,在它之前出現的位置減1,然後我們在主席樹詢問區間的時候每個數都只出現一次了,就不用二分去找那個位置了,時間複雜度退化成O(nlog(n))

程式碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<vector>
#include<bitset>
#include<set>
#include<queue>
#include<stack> #include<map> #include<cstdlib> #include<cmath> #define PI 2*asin(1.0) #define LL long long #define pb push_back #define pa pair<int,int> #define clr(a,b) memset(a,b,sizeof(a)) #define lson lr<<1,l,mid #define rson lr<<1|1,mid+1,r #define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)
#define key_value ch[ch[root][1]][0] const int MOD = 1000000007; const int N = 2e5 + 15; const int maxn = 100+ 14; const int letter = 130; const int INF = 1e9; const double pi=acos(-1.0); const double eps=1e-8; using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,q,pre[N],a[N],sum[N*36],ls[N*36],rs[N*36],root[N]; int siz,ps[N]; void insert(int x,int &y,int l,int r,int d,int v){ y=++siz; ls[y]=ls[x],rs[y]=rs[x],sum[y]=sum[x]+v; if(l==r) return; int mid=(l+r)>>1; if(d<=mid) insert(ls[x],ls[y],l,mid,d,v); else insert(rs[x],rs[y],mid+1,r,d,v); } int query(int x,int l,int r,int ll,int rr){ if(ll<=l&&r<=rr) return sum[x]; int mid=(l+r)>>1; int ans=0; if(ll<=mid) ans+=query(ls[x],l,mid,ll,rr); if(rr>mid) ans+=query(rs[x],mid+1,r,ll,rr); return ans; } int find_k(int x,int l,int r,int k){ if(l==r) return l; int mid=(l+r)>>1; if(sum[ls[x]]>=k) return find_k(ls[x],l,mid,k); else return find_k(rs[x],mid+1,r,k-sum[ls[x]]); } int main(){ int T,cas=0; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&q); clr(pre,0),siz=0; clr(root,0); for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=n;i;i--){ insert(root[i+1],root[i],1,n,i,1); if(pre[a[i]]) insert(root[i],root[i],1,n,pre[a[i]],-1); pre[a[i]]=i; } ps[0]=0; for(int i=1;i<=q;i++){ int l,r; scanf("%d%d",&l,&r); l=(l+ps[i-1])%n+1,r=(r+ps[i-1])%n+1; if(l>r) swap(l,r); int mid=query(root[l],1,n,l,r); mid=(mid+1)/2; ps[i]=find_k(root[l],1,n,mid); } printf("Case #%d:",++cas); for(int i=1;i<=q;i++) printf(" %d",ps[i]); puts(""); } return 0; }