hdu 5919--Sequence II(主席樹--求區間不同數個數+區間第k大)
阿新 • • 發佈:2017-10-11
positions minus -s ima date rst itl 主席樹 技術
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.
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}
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.
題目鏈接
Problem Description 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
Note that ki is the number of different integers in this subsequence. You should output p(i)⌈ki2⌉for the i-th query.
Input 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
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)
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}
Output 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.
Sample Input 2 5 2 3 3 1 5 4 2 2 4 4 5 2 2 5 2 1 2 2 3 2 4
Sample Output Case #1: 3 3 Case #2: 3 1 Hint 題意:一個有n個數的序列,現在有m次詢問,每次給一個區間(l,r),設區間中有k個不同的數,它們在區間中第一次出現的位置為p1,p2 ,……,pk 並且將它們排序p1<p2<……<pk,現在求p[(k+1)/2]的值? 思路:主席樹記錄當前數出現的位置,即每次在當前數出現的位置(下標)+1,對於序列數a[1]~a[n]建立主席樹時,如果當前這個數之前出現過,那麽在當前這個版本線段樹上對前一次出現的位置-1,在當前位置+1,這樣就可以求出區間不同數的個數。現在要求出區間第k大,那麽可以從a[n]~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[N],ans[N]; int t[N],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大)