傳送門:Sequence II
題目大意
這個題目讀題是個大困難呀,不好讀;
給定一個長度爲n的串,q次查詢每次查詢
解題思路
主席樹的套路題目;知道主席樹的人一定做過主席樹的兩種應用的題目就是求給定區間的第K大,還有給定區間
這個題目就是對主席樹的這兩個應用的綜合考察,我們先把這個序列從後向前的按照位置插入主席樹,這樣就能避免後面出現重複數字對前面的影響,然後我們求出這個區間中有k個不同的數字,我們只需要求出這個區間中第
AC代碼
#include <cstdio>
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
const int MX = 2e5+5;
const int N = MX*40;
int n,q,tot;
int A[MX];
int T[N],lson[N],rson[N],sum[N];
int build(int l,int r)
{
int rt = tot++;
sum[rt] = 0;
int mid = (l+r)>>1;
if(l!=r) {
lson[rt] = build(l,mid);
rson[rt] = build(mid+1,r);
}
return rt;
}
int update(int rt,int pos,int val)
{
int nrt = tot++;
int tmp = nrt;
int l=1,r=n;
sum[nrt] = sum[rt] + val;
while(l<r) {
int mid = (l+r)>>1;
if(pos<=mid) {
lson[nrt] = tot++;
rson[nrt] = rson[rt];
nrt = lson[nrt];
rt = lson[rt];
r = mid;
} else {
rson[nrt] = tot++;
lson[nrt] = lson[rt];
nrt = rson[nrt];
rt = rson[rt];
l = mid+1;
}
sum[nrt] = sum[rt]+val;
}
return tmp;
}
int query(int rt,int pos)
{
int cnt = 0;
int l = 1,r = n;
while(pos < r)
{
int mid = (l + r) >> 1;
if(pos <= mid)
{
rt = lson[rt];
r = mid;
}
else
{
cnt += sum[lson[rt]];
rt = rson[rt];
l = mid + 1;
}
}
return cnt + sum[rt];
}
int Query(int rt,int k)
{
int l = 1,r = n;
while(l < r){
int mid = (l + r) >> 1;
if(sum[lson[rt]] >= k){
rt = lson[rt];
r = mid;
}
else{
k -= sum[lson[rt]];
rt = rson[rt];
l = mid +1 ;
}
}
return l;
}
int main()
{
int _;
// freopen("in.txt","r",stdin);
scanf("%d",&_);
for(int cas=1;cas<=_;cas++) {
tot=0;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&A[i]);
T[n+1] = build(1,n);
map<int,int>mp;
for(int i=n;i>0;i--) {
if(mp.find(A[i])==mp.end()) T[i] = update(T[i+1],i,1);
else {
int tmp = update(T[i+1],mp[A[i]],-1);
T[i] = update(tmp,i,1);
}
mp[A[i]] = i;
}
int ans = 0;
printf("Case #%d:",cas);
while(q--) {
int l,r;
scanf("%d%d",&l,&r);
l = (l+ans)%n+1;
r = (r+ans)%n+1;
int ll = min(l,r),rr = max(l,r);
int k = (query(T[ll],rr)+1)>>1;
if(!k) k=1;
ans = Query(T[ll],k);
printf(" %d",ans);
}
puts("");
}
return 0;
}