HDU 5919 Sequence II
CCPC长春赛区现场赛的题,可惜自己太菜,当时不会做,听了老哥的教训后,决定好好学习主席树。
思路:考虑每个点带来的影响。
显然,若从前向后考虑,对于第i个数,对结果的影响仅为
1. 若该数字未出现过,添加一个新位置i
2. 若出现过,无操作。
但是“这种影响是不全面的”,因为它无法表现从i起始时的结果。
如果从后向前考虑,每个点对结果的影响为
1. 更新某个数字出现的位置。
2.1 若该数字未出现过,则添加新的位置
2.2 若出现过,则消去前面曾经出现的位置,并添加新的位置
我们可以表现从任意起始时的结果。
#include <iostream>
#include <cstdio>
#include<cstring>
#include <algorithm>
using namespace std;
#define lson tn[x].ls
#define rson tn[x].rs
const int maxn = 200000;
struct TreeNode {
int ls, rs; //左右子节点
int value; //值
};
TreeNode tn[maxn * 50];
int POS, VALUE;
int cnt;
int N, M;
int a[maxn + 10], mp[maxn + 10];
int tr[maxn + 10]; //tr[i] 树根i的节点编号
int node(int v, int ls, int rs) {
tn[cnt].value = v;
tn[cnt].ls = ls;
tn[cnt].rs = rs;
return cnt ++;
}
void Maintain(int x) {
tn[x].value = tn[lson].value + tn[rson].value;
}
/*
* 建空树
*/
void Build(int &x, int l = 1, int r = N) {
x = node(0, -1, -1);
if(l == r) {
return;
}
int mid = (l + r) >> 1;
Build(lson, l, mid);
Build(rson, mid + 1, r);
}
/*
* 插入新节点
*/
void Insert(int pre, int &x, int l = 1, int r = N) {
x = node(tn[pre].value, tn[pre].ls, tn[pre].rs);
if(l == r) {
tn[x].value = VALUE;
return;
}
int m = (l + r) >> 1;
if(POS <= m) {
Insert(lson, lson, l, m);
} else {
Insert(rson, rson, m + 1, r);
}
Maintain(x);
}
/*
* 查找根为x时的,前k个数的和
*/
int Query(int x, int ll, int rr, int l = 1, int r = N) {
if(ll <= l && r <= rr) {
return tn[x].value;
}
int m = (l + r) >> 1;
int ans = 0;
if(ll <= m)
ans += Query(lson, ll, rr, l, m);
if(rr > m) {
ans += Query(rson, ll, rr, m + 1, r);
}
return ans;
}
/*
* 查找根为x时的,第k个数
*/
int Find(int x, int k, int l = 1, int r = N) {
if(l == r) {
return l;
}
int tmp = tn[lson].value;
int m = (l + r) >> 1;
if(k <= tmp)return Find(lson, k, l, m);
else return Find(rson, k - tmp, m + 1, r);
}
int main() {
int T, k;
scanf("%d", &T);
for(int CASE = 1; CASE <= T; CASE++) {
memset(mp, -1, sizeof(mp));
scanf("%d%d", &N, &M);
for(int i = 1; i <= N; i ++) {
scanf("%d", &a[i]);
}
cnt = 1;
Build(tr[N + 1]);
for(int i = N; i > 0; i --) {
if(mp[a[i]] == -1) {
POS = i;
VALUE = 1;
Insert(tr[i + 1], tr[i]);
} else {
POS = i;
VALUE = 1;
Insert(tr[i + 1], tr[i]);
POS = mp[a[i]];
VALUE = 0;
Insert(tr[i], tr[i]);
}
mp[a[i]] = i;
}
int ans = 0;
printf("Case #%d:", CASE);
while(M --) {
int l, r;
scanf("%d%d", &l, &r);
l = (l + ans) % N + 1;
r = (r + ans) % N + 1;
if(r < l) swap(l, r);
int all = Query(tr[l], l, r);
printf(" %d", ans = Find(tr[l], (all + 1) >> 1));
}
puts("");
}
return 0;
}