题目大意:
给一个长度为n的序列.给Q次询问,每次询问 [ L , R ] [L,R] [L,R].假设里面有 k k k个不同的数.求从左到右第 ⌈ k 2 ⌉ \lceil\frac{k}{2}\rceil ⌈2k⌉个不同的数出现的位置.( n , q ≤ 2 e 5 n,q \leq 2e5 n,q≤2e5).强制在线.
题目思路:
前置知识点:主席树求区间不同的数的个数:(个人认为知道这个点,这道题就做完80%了)
https://blog.csdn.net/qq_35577488/article/details/109018868
这里需要求的是从左到右的位置.顺序建树行不通(因为我们只保存一个数最后出现的位置,与题目意思不相符合).
那么自然想到逆序建树,查询 [ L , R ] [L,R] [L,R]时,先查询区间不同数个数.再直接对第 L L L颗树查询 第 ⌈ k 2 ⌉ \lceil\frac{k}{2}\rceil ⌈2k⌉个 贡献1 出现的位置即可.(都是基操…)
一道银牌题,还不错.难度适中
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define mid ((l + r) >> 1)
const int maxn = 4e5 + 5;
int sum[maxn << 5] , ls[maxn << 5] , rs[maxn << 5] , rt[maxn] , tot;
int add (int l , int r , int t , int p , int c)
{
int now = ++tot;
ls[now] = ls[t];
rs[now] = rs[t];
sum[now] = sum[t] + c;
if (l == r) return now;
if (p <= mid) ls[now] = add (l , mid , ls[now] , p , c);
else rs[now] = add (mid + 1 , r , rs[now] , p , c);
return now;
}
int ask_num (int t , int l , int r , int L , int R)
{
if (L > R) return 0;
if (L <= l && r <= R) return sum[t];
int ans = 0;
if (L <= mid) ans += ask_num(ls[t] , l , mid , L , R);
if (R > mid) ans += ask_num(rs[t] , mid + 1 , r , L , R);
return ans;
}
int ask_pos (int t , int l , int r , int k)
{
if (l == r) return l;
if (sum[ls[t]] >= k) return ask_pos(ls[t] , l , mid , k);
return ask_pos(rs[t] , mid + 1 , r , k - sum[ls[t]]);
}
int last[maxn] , a[maxn] , n , m;
int main()
{
int t; scanf("%d" , &t);
int ca = 0;
while (t--){
tot = 0;
scanf("%d%d" , &n , &m);
memset (last , 0 , sizeof last);
for (int i = 0 ; i <= n ; i++){
rt[i] = 0;
}
int up = n << 5;
for (int i = 0; i <= up ; i++){
sum[i] = ls[i] = rs[i] = 0;
}
rt[n + 1] = 0;
for (int i = 1; i <= n ; i++){
scanf("%d" , a + i);
}
for (int i = n; i >= 1 ; i--){
if (last[a[i]]){
rt[i] = add (1 , n , rt[i + 1] , last[a[i]] , -1);
rt[i] = add (1 , n , rt[i] , i , 1);
}else {
rt[i] = add (1 , n , rt[i + 1] , i , 1);
}
last[a[i]] = i;
}
int lastans = 0;
printf("Case #%d: " , ++ca);
while (m--){
int l , r , x ,y;scanf("%d%d" , &x , &y);
l = min((x + lastans) % n + 1 ,(y + lastans) % n + 1);
r = max((x + lastans) % n + 1 ,(y + lastans) % n + 1);
int k = ask_num(rt[l] , 1 , n , l , r);
k = (k - 1) / 2 + 1;
lastans = ask_pos(rt[l] , 1 , n , k);
if (m == 0)
printf("%d\n" , lastans);
else
printf("%d " , lastans);
}
}
return 0;
}