题意
给一个数列,每次询问一个区间内有没有一个数出现次数超过一半
Solution
主席树入门题。
显然一个区间内出现次数超过一半的数最多只有一个。
查询类似普通的区间第k大问题。
判断左区间内出现的数的次数,如果大于一半,则左区间内有可能有答案(此时右区间肯定没有),如果右区间大于一半同理。
如果都不大于一半则显然没有答案。
#include <iostream> #include <cstdio> using namespace std; const int N = 500010; struct Chairman_Tree{ int ls, rs; int val; }tr[N * 30]; int rt[N], tot; int n, m; int a[N]; void ins(int &cur, int pre, int l, int r, int pos) { cur = ++tot, tr[cur] = tr[pre], tr[cur].val++; if (l == r) return; int mid = (l + r) >> 1; if (pos <= mid) ins(tr[cur].ls, tr[pre].ls, l, mid, pos); else ins(tr[cur].rs, tr[pre].rs, mid + 1, r, pos); } int ask(int p, int q, int l, int r, int k) { if (l == r) return l; int mid = (l + r) >> 1; int num_l = tr[tr[q].ls].val - tr[tr[p].ls].val; int num_r = tr[tr[q].rs].val - tr[tr[p].rs].val; if (num_l > k) return ask(tr[p].ls, tr[q].ls, l, mid, k); else if (num_r > k) return ask(tr[p].rs, tr[q].rs, mid + 1, r, k); else return 0; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); ins(rt[i], rt[i - 1], 1, n, a[i]); } while (m--) { int l, r; scanf("%d%d", &l, &r); printf("%d ", ask(rt[l - 1], rt[r], 1, n, (r - l + 1) >> 1)); } return 0; }