HDU 5919 -- Sequence II (主席树)
题意:
给一串数字,每个数字的位置是这个数第一次出现的位置。
每个询问对于序列的一个子区间,设一共有k个不同的数,求第ceil(k/2)个数的位置。
因为强制在线,所以离线乱搞pass掉。
主席树可解。
考虑一个数列:
p 1 2 3 4 5 6 // 原序列标号
a : 1 2 1 2 3 4 // 原序列
p1 1 2 1 2 5 6 // 子序列开始下标为1
p2 2 3 1 5 6
p3 3 4 5 6
p4 4 5 6
p5 5 6
p6 6
有一个规律就是对于以L为开始的子序列来说,只要求出[L, N]的子区间,R是不影响P(L)数组的。
那么就想到将数组倒过来建主席树。
树里存的是什么呢????
存的是…【此处想了10分钟……】…区间内不同数的个数(只考虑第一次出现的)
那么在用一个数组记录每个数第一个出现的位置,每添加一个数,该位置+1,如果一个数之前出现过,那么就要更改之前第一次出现的位置-1。
不是很会主席树,之前就写过一道模板题= = 强行没看题解,一顿乱搞还是搞出来了,但是估计写的很麻烦
#include <bits/stdc++.h> using namespace std; const int N = 200005; struct node { int l, r, v; } T[N*40]; int a[N]; int pos[N]; int root[N], cnt; int ans; // y is x previous version void update(int l, int r, int &x, int y, int p, int v) { T[++cnt] = T[y], T[cnt].v += v; x = cnt; if (l == r) return ; int mid = (l+r) >> 1; if (mid >= p) update(l, mid, T[x].l, T[y].l, p, v); else update(mid+1, r, T[x].r, T[y].r, p, v); } // p1 > p2 void update(int l, int r, int &x, int y, int p1, int v1, int p2, int v2) { T[++cnt] = T[y]; x = cnt; if (l == r) return ; int mid = (l+r) >> 1; // three conditions // p1 > mid >= p2, p1 > p2 > mid, mid >= p1 > p2 if (p1 > mid && p2 <= mid) { update(mid+1, r, T[x].r, T[y].r, p1, v1); update(l, mid, T[x].l, T[y].l, p2, v2); } else if (p2 > mid) { update(mid+1, r, T[x].r, T[y].r, p1, v1, p2, v2); } else { update(l, mid, T[x].l, T[y].l, p1, v1, p2, v2); } } void query(int l, int r, int x, int k) { if (l == r) { ans = l; return ; } int mid = (l+r) >> 1; if (T[T[x].r].v >= k) { ans = mid+1; query(mid+1, r, T[x].r, k); } else { query(l, mid, T[x].l, k-T[T[x].r].v); } } int query(int l, int r, int x, int L, int R) { if (l >= L && r <= R) return T[x].v; int mid = (l+r) >> 1; int ans = 0; if (mid >= L) ans += query(l, mid, T[x].l, L, R); if (mid < R) ans += query(mid+1, r, T[x].r, L, R); return ans; } int main() { //freopen("in.txt", "r", stdin); int t, cas = 0; scanf("%d", &t); while (t--) { printf("Case #%d:", ++cas); ans = 0; int n, q, l_, r_, l, r, k; scanf("%d%d", &n, &q); memset(pos, 0, sizeof pos); cnt = 0; for (int i = 1; i <= n; ++i) scanf("%d", &a[n-i+1]); for (int i = 1; i <= n; ++i) { if (pos[a[i]]) update(1, n, root[i], root[i-1], i, 1, pos[a[i]], -1); else update(1, n, root[i], root[i-1], i, 1); pos[a[i]] = i; } while (q--) { scanf("%d%d", &l_, &r_); l_ = (l_ + ans) % n + 1; r_ = (r_ + ans) % n + 1; l = min(l_, r_); r = max(l_, r_); l = n-l+1, r = n-r+1; swap(l, r); k = query(1, n, root[r], l, r); query(1, n, root[r], ceil(k/2.0)); ans = n-ans+1; printf(" %d", ans); } printf("\n"); } return 0; }