hdu 5919--Sequence II(主席树--求区间不同数个数+区间第k大)
2017-10-11 17:08
447 查看
题目链接
[align=left]Problem Description[/align]
Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,an There are m queries.
In the i-th query, you are given two integers li and ri. Consider the subsequence 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 as p(i)1,p(i)2,⋯,p(i)ki (in ascending order, i.e.,p(i)1<p(i)2<⋯<p(i)ki).
Note that ki is the number of different integers in this subsequence. You should output p(i)⌈ki2⌉for the i-th query.
[align=left]Input[/align]
In the first line of input, there is an integer T (T≤2) denoting the number of test cases.
Each test case starts with two integers n (n≤2×105) and m (m≤2×105). There are n integers in the next line, which indicate the integers in the sequence(i.e., a1,a2,⋯,an,0≤ai≤2×105).
There are two integers li and ri in the following m lines.
However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to l‘i,r‘i(1≤l‘i≤n,1≤r‘i≤n). As a result, the problem became more exciting.
We can denote the answers as ans1,ans2,⋯,ansm. Note that for each test case ans0=0.
You can get the correct input li,ri from what you read (we denote them as l‘i,r‘i)by the following formula:
li=min{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) mod n+1}
ri=max{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) mod n+1}
[align=left]Output[/align]
You should output one single line for each test case.
For each test case, output one line “Case #x: p1,p2,⋯,pm”, where x is the case number (starting from 1) and p1,p2,⋯,pm is the answer.
[align=left]Sample Input[/align]
2
5 2
3 3 1 5 4
2 2
4 4
5 2
2 5 2 1 2
2 3
2 4
[align=left]Sample Output[/align]
Case #1: 3 3
Case #2: 3 1
Hint
![](http://acm.split.hdu.edu.cn/data/images/C728-1009-1.jpg)
题意:一个有n个数的序列,现在有m次询问,每次给一个区间(l,r),设区间中有k个不同的数,它们在区间中第一次出现的位置为p1,p2 ,……,pk 并且将它们排序p1<p2<……<pk,现在求p[(k+1)/2]的值?
思路:主席树记录当前数出现的位置,即每次在当前数出现的位置(下标)+1,对于序列数a[1]~a
建立主席树时,如果当前这个数之前出现过,那么在当前这个版本线段树上对前一次出现的位置-1,在当前位置+1,这样就可以求出区间不同数的个数。现在要求出区间第k大,那么可以从a
~a[1]建立线段树,然后直接求k大就行。
代码如下:
[align=left]Problem Description[/align]
Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,an There are m queries.
In the i-th query, you are given two integers li and ri. Consider the subsequence 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 as p(i)1,p(i)2,⋯,p(i)ki (in ascending order, i.e.,p(i)1<p(i)2<⋯<p(i)ki).
Note that ki is the number of different integers in this subsequence. You should output p(i)⌈ki2⌉for the i-th query.
[align=left]Input[/align]
In the first line of input, there is an integer T (T≤2) denoting the number of test cases.
Each test case starts with two integers n (n≤2×105) and m (m≤2×105). There are n integers in the next line, which indicate the integers in the sequence(i.e., a1,a2,⋯,an,0≤ai≤2×105).
There are two integers li and ri in the following m lines.
However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to l‘i,r‘i(1≤l‘i≤n,1≤r‘i≤n). As a result, the problem became more exciting.
We can denote the answers as ans1,ans2,⋯,ansm. Note that for each test case ans0=0.
You can get the correct input li,ri from what you read (we denote them as l‘i,r‘i)by the following formula:
li=min{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) mod n+1}
ri=max{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) mod n+1}
[align=left]Output[/align]
You should output one single line for each test case.
For each test case, output one line “Case #x: p1,p2,⋯,pm”, where x is the case number (starting from 1) and p1,p2,⋯,pm is the answer.
[align=left]Sample Input[/align]
2
5 2
3 3 1 5 4
2 2
4 4
5 2
2 5 2 1 2
2 3
2 4
[align=left]Sample Output[/align]
Case #1: 3 3
Case #2: 3 1
Hint
![](http://acm.split.hdu.edu.cn/data/images/C728-1009-1.jpg)
题意:一个有n个数的序列,现在有m次询问,每次给一个区间(l,r),设区间中有k个不同的数,它们在区间中第一次出现的位置为p1,p2 ,……,pk 并且将它们排序p1<p2<……<pk,现在求p[(k+1)/2]的值?
思路:主席树记录当前数出现的位置,即每次在当前数出现的位置(下标)+1,对于序列数a[1]~a
建立主席树时,如果当前这个数之前出现过,那么在当前这个版本线段树上对前一次出现的位置-1,在当前位置+1,这样就可以求出区间不同数的个数。现在要求出区间第k大,那么可以从a
~a[1]建立线段树,然后直接求k大就行。
代码如下:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <map> using namespace std; typedef long long LL; const int N=2e5+5; int a ,ans ; int t ,tot; map<int,int>mp; struct Node { int l,r; int num; }tr[40*N]; void init() { tot=0; mp.clear(); } int build(int l,int r) { int ii=tot++; tr[ii].num=0; if(l<r) { int mid=(l+r)>>1; tr[ii].l=build(l,mid); tr[ii].r=build(mid+1,r); } return ii; } int update(int now,int l,int r,int x,int y) { int ii=tot++; tr[ii].num=tr[now].num+y; tr[ii].l=tr[now].l; tr[ii].r=tr[now].r; if(l<r) { int mid=(l+r)>>1; if(x<=mid) tr[ii].l=update(tr[now].l,l,mid,x,y); else tr[ii].r=update(tr[now].r,mid+1,r,x,y); } return ii; } int query(int now,int l,int r,int L,int R) { if(L<=l&&r<=R) return tr[now].num; int mid=(l+r)>>1; int sum=0; if(mid>=L) sum+=query(tr[now].l,l ,mid,L,R); if(mid<R) sum+=query(tr[now].r,mid+1,r,L,R); return sum; } int finds(int now,int l,int r,int k) { if(l==r) return l; int mid=(l+r)>>1; if(tr[tr[now].l].num>=k) return finds(tr[now].l,l,mid,k); else return finds(tr[now].r,mid+1,r,k-tr[tr[now].l].num); } int main() { int T,Case=1; cin>>T; while(T--) { init(); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); t[n+1]=build(1,n); for(int i=n;i>=1;i--) { if(mp.count(a[i])) { int tmp=update(t[i+1],1,n,mp[a[i]],-1); t[i]=update(tmp,1,n,i,1); } else t[i]=update(t[i+1],1,n,i,1); mp[a[i]]=i; } ans[0]=0; for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); int l=min((x+ans[i-1])%n+1,(y+ans[i-1])%n+1); int r=max((x+ans[i-1])%n+1,(y+ans[i-1])%n+1); int k=(query(t[l],1,n,l,r)+1)/2; ans[i]=finds(t[l],1,n,k); } printf("Case #%d:",Case++); for(int i=1;i<=m;i++) printf(" %d",ans[i]); puts(""); } return 0; } /** 10 4 1 1 1 1 1 1 1 1 1 1 3 6 6 8 7 10 2 5 */
相关文章推荐
- HDU 5919 Sequence II(主席树+区间不同数个数+区间第k小)
- HDU 5919 Sequence II (主席树+求区间不同数个数)
- hdu 5919 Sequence II(主席树,求区间不同数的个数)
- hdu 5919 主席树(区间不同数个数+区间第k个数)
- HDU 5919 Sequence II (主席树,不同元素个数+第K大)
- hdu 5919 Sequence II (主席树,求区间不同数的个数)
- hdu 5919 主席树(区间不同数的个数 + 区间第k大)
- hdu5919 Sequence II(主席树,区间第k大)
- Hdu-5919 Sequence II(主席树在线求区间不同数)
- hdu5919 Sequence II(主席树求区间数种数和k大查找)
- POJ 2104 & HDU 2665 & POJ 2761 K-th Number (主席树入门题 区间第K大)
- HDU 2665 / POJ 2104 静态区间第k小 主席树
- HDU 5919 Sequence II(主席树)
- hdu 2665 区间第K大 主席树入门
- hdu_5919_Sequence II(主席树)
- HDU 2665 主席树(求区间第k大模板)
- hdu 5919 Sequence II(主席树)
- [置顶] HDU 5919 Sequence II(主席树)
- HDU2665 主席树原理解决静态区间第K大值问题总结 有详细图解和代码解释
- SPOJ DQUERY - D-query(主席树 ,求区间不同的数个数)