「JSOI2011」棒棒糖

「JSOI2011」棒棒糖

传送门
双倍经验
考虑主席树做法。
对于当前的主席树节点,如果 \(\le mid\) 的个数足够就往左边走,否则就尝试往右边走,都不行就返回 \(0\)
参考代码:

#include <algorithm>
#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}
 
const int _ = 5e4 + 5;
 
int n, m, a[_], tot, rt[_];
struct node { int lc, rc, cnt; } t[_ << 5];
 
inline void build(int& p, int l = 1, int r = n) {
    p = ++tot;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    build(t[p].lc, l, mid), build(t[p].rc, mid + 1, r);
}
 
inline void update(int& p, int q, int x, int l = 1, int r = n) {
    t[p = ++tot] = t[q], ++t[p].cnt;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    if (x <= mid) update(t[p].lc, t[q].lc, x, l, mid);
    else update(t[p].rc, t[q].rc, x, mid + 1, r);
}
 
inline int query(int p, int q, int v, int l = 1, int r = n) {
    if (l == r) return l;
    int mid = (l + r) >> 1;
    if ((t[t[p].lc].cnt - t[t[q].lc].cnt) * 2 > v) return query(t[p].lc, t[q].lc, v, l, mid);
    if ((t[t[p].rc].cnt - t[t[q].rc].cnt) * 2 > v) return query(t[p].rc, t[q].rc, v, mid + 1, r);
    return 0;
}
 
int main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    read(n), read(m);
    for (rg int i = 1; i <= n; ++i) read(a[i]);
    build(rt[0]);
    for (rg int i = 1; i <= n; ++i) update(rt[i], rt[i - 1], a[i]);
    for (rg int l, r; m--; ) read(l), read(r), printf("%d\n", query(rt[r], rt[l - 1], r - l + 1));
    return 0;
}
posted @ 2020-01-31 18:37  Sangber  阅读(134)  评论(0编辑  收藏  举报