题目链接:https://cn.vjudge.net/problem/HDU-5919
题意:给你n个数,m个区间询问,找出区间内每种数字第一次出现的下标,然后找出下标里的中位数
这个题可以倒着把数字更新,维护区间内不同数字出现的次数,对于每个历史版本维护的是最左边的第一次出现的数字
#include
using namespace std;
const int maxn = 2e5 + 10;
struct node{
int l, r, val;
}e[maxn *41];
int a[maxn], root[maxn], cnt;
inline void build(int l, int r, int &cur){
cur = ++cnt;
e[cur].val = 0;
if(l == r){
return;
}
int mid = l + r >> 1;
build(l, mid, e[cur].l);
build(mid + 1, r, e[cur].r);
}
inline void update(int pre, int &cur, int L, int R, int pos, int val){
cur = ++cnt;
e[cur] = e[pre];
e[cur].val += val;
if(L == R)return;
int mid = L + R >> 1;
if(pos <= mid) update(e[pre].l, e[cur].l, L, mid, pos, val);
else update(e[pre].r, e[cur].r, mid + 1, R, pos, val);
}
inline int queryI(int l, int r, int cur, int cl, int cr){
if(cl <= l && r <= cr) return e[cur].val;
int mid = l + r >> 1;
int ans = 0;
if(cl <= mid) ans += queryI(l, mid, e[cur].l, cl, cr);
if(cr > mid) ans += queryI(mid + 1, r, e[cur].r, cl, cr);
return ans;
}
inline int queryII(int l, int r, int cur, int k){
if(l == r){
return l;
}
int mid = l + r >> 1;
if(k <= e[e[cur].l].val) {
return queryII(l, mid, e[cur].l, k);
}
else return queryII(mid + 1, r, e[cur].r, k - e[e[cur].l].val);
}
int res[maxn];
int mp[maxn];
int main(){
int T, n, m, cas = 1;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
cnt = 0;
build(1, n, root[n + 1]);
memset(mp, 0, sizeof(mp));
for(int i = n; i >= 1; i--) {
update(root[i + 1], root[i], 1, n, i, 1);
if(mp[a[i]])
update(root[i], root[i], 1, n, mp[a[i]], -1);
mp[a[i]] = i;
}
int ans = 0, l, r;
for(int i = 1; i <= m; i++) {
scanf("%d%d", &l, &r);
l=(l + ans) % n + 1;
r=(r + ans) % n + 1;
if(l > r) swap(l, r);
int k = queryI(1, n, root[l], l, r);
k = (k + 1) >> 1;
ans = queryII(1, n, root[l], k);
res[i] = ans;
}
printf("Case #%d:", cas++);
for(int i = 1; i <= m; i++) {
printf(" %d", res[i]);
}
printf("\n");
}
return 0;
}