hdu 5919 主席树保留区间数的种类数目
Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,an a1,a2,⋯,anThere
are m queries.
In the i-th query, you are given two integersli li and ri ri.
Consider the subsequence ali,ali+1,ali+2,⋯,ari ali,ali+1,ali+2,⋯,ari.
We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence asp(i)1,p(i)2,⋯,p(i)ki p1(i),p2(i),⋯,pki(i) (in
ascending order, i.e.,p(i)1<p(i)2<⋯<p(i)ki p1(i)<p2(i)<⋯<pki(i)).
Note thatki ki is
the number of different integers in this subsequence. You should output p(i)⌈ki2⌉ p⌈ki2⌉(i)for
the i-th query.
In the i-th query, you are given two integers
We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as
Note that
Each test case starts with two integers n (
There are two integers
However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to
We can denote the answers as
You can get the correct input
For each test case, output one line “Case #x:
2 5 2 3 3 1 5 4 2 2 4 4 5 2 2 5 2 1 2 2 3 2 4
Case #1: 3 3
Case #2: 3 1
给你n(n≤2∗105 )个数,每个数的大小0<Ai≤2∗105 。再给你m(m≤2∗105 )个询问。对于每个询问输入l,r,表示Al...Ar 这个区间我们得到每个数第一次出现的位置下标的排列,假设这个区间有k个不同的数,我们得到的排列是p1<p2<p3<...<pk ,叫你求第(k+1)/2这个数是多少?
首先 要想清楚的是 我们用主席树来记录位置i,而不是值a[i]
从后往前,复制旧的到新的,添加到新的位置,删掉旧的位置,记录 sum数组 代表区间的 值的个数,然后就是一个类似于线段树的操作了
题解:
1、我们利用主席树记录相同的数的前一个位置是多少,很容易得到区间有多少个不同的数,但是我们要得到第(k+1)/2这个数的话我们要二分去求解。时间复杂度为
O(n∗log2(n)) ,,在hdu会超时。2、如果我们从后往前的话在当前位置
i 我们在主席树上i这个位置加1,在它之前出现的位置减1,然后我们在主席树询问区间的时候每个数都只出现一次了,就不用二分去找那个位置了,时间复杂度退化成O(n∗log(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 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; } struct node { int lson,rson,sum; }T[36*N]; int n,q,pre[N],a[N],root[N]; int siz,ps[N]; void insert(int x,int &y,int l,int r,int d,int v){ y=++siz; T[y]=T[x],T[y].sum+=v; if(l==r) return; int mid=(l+r)>>1; if(d<=mid) insert(T[x].lson,T[y].lson,l,mid,d,v); else insert(T[x].rson,T[y].rson,mid+1,r,d,v); } int query(int x,int l,int r,int ll,int rr){ if(ll<=l&&r<=rr) return T[x].sum; int mid=(l+r)>>1; int ans=0; if(ll<=mid) ans+=query(T[x].lson,l,mid,ll,rr); if(rr>mid) ans+=query(T[x].rson,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(T[T[x].lson].sum>=k) return find_k(T[x].lson,l,mid,k); else return find_k(T[x].rson,mid+1,r,k-T[T[x].lson].sum); } 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],0,n,i,1); if(pre[a[i]]) insert(root[i],root[i],0,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],0,n,l,r); mid=(mid+1)/2; ps[i]=find_k(root[l],0,n,mid); } printf("Case #%d:",++cas); for(int i=1;i<=q;i++) printf(" %d",ps[i]); puts(""); } return 0; }