[hdu 5919 Sequence II] 主席树
1. 题目链接
2. 题意描述
给定一个序列
a1,a2,…,an
,有
m
次查询,每次查询一个区间
3. 解题思路
首先,我们需要用主席树求出区间不同数
k
。然后就是找中位数
我们需要逆序建立主席树【正序建立的主席树,记录的是最后一个出现的位置,而不是第一个出现的位置】,然后这样才求出距离区间左边界
⌈k2⌉
的点的位置。【其实这个查询的过程就是跟求区间第
k
<script type="math/tex" id="MathJax-Element-165">k</script>大的过程一样】。
4. 参考代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
#define __mid__ int mid = ((l + r) >> 1)
typedef pair<int, int> PII;
const int MX = 2e5 + 5;
const int MM = 19 * 2 * MX;
const int INF = 0x3f3f3f3f;
int T, N, M, cas;
struct TNode {
int ls, rs, sum;
} node[MM]; /// (N + 1) * 2 * log(200000) = 18 * MX * 2;
int root[MX], id;
void build(int l, int r, int& rt) {
rt = id ++;
node[rt].sum = 0;
if(l == r) {
node[rt].ls = node[rt].rs = -1;
return;
}
__mid__;
build(l, mid, node[rt].ls);
build(mid + 1, r, node[rt].rs);
}
void update(const int& pos, const int& v, int l, int r, int prt, int& rt) {
rt = id ++;
node[rt] = node[prt];
node[rt].sum += v;
if(l == r) return;
__mid__;
if(pos <= mid) update(pos, v, l, mid, node[prt].ls, node[rt].ls);
else update(pos, v, mid + 1, r, node[prt].rs, node[rt].rs);
}
int getAns(int x, int l, int r, int rt) {
if(l == r) return l;
__mid__;
if(node[node[rt].ls].sum >= x) return getAns(x, l, mid, node[rt].ls);
else return getAns(x - node[node[rt].ls].sum, mid + 1, r, node[rt].rs);
}
int query(const int& L, const int& R, int l, int r, int rt) {
if(L <= l && r <= R) return node[rt].sum;
__mid__;
int ret = 0;
if(L <= mid) ret += query(L, R, l, mid, node[rt].ls);
if(R > mid) ret += query(L, R, mid + 1, r, node[rt].rs);
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d", &T);
cas = 0;
while(T --) {
id = 0;
scanf("%d %d", &N, &M);
build(1, N, root[N + 1]);
vector<int> A(MX), F(MX, -1);
for(int i = 1; i <= N; i++) scanf("%d", &A[i]);
for(int i = N; i >= 1; i--) {
int rt, & x = A[i];
if(F[x] != -1) {
update(F[x], -1, 1, N, root[i + 1], rt);
update(i, 1, 1, N, rt, root[i]);
} else {
update(i, 1, 1, N, root[i + 1], root[i]);
}
F[x] = i;
}
int ans = 0;
printf("Case #%d:", ++cas);
for(int i = 1; i <= M; i++) {
int L, R; scanf("%d %d", &L, &R);
L = (L + ans) % N + 1, R = (R + ans) % N + 1;
if(L > R) swap(L, R);
int k = query(L, R, 1, N, root[L]), x = (k + 1) >> 1;
ans = getAns(x, 1, N, root[L]);
printf(" %d", ans);
}
printf("\n");
}
return 0;
}