左转弱化版:https://www.cnblogs.com/zcr-blog/p/12736587.html
题目描述
题解
和弱化版的思路一样,如果左子树中出现的次数大于要求,则左子树中就可能存在答案,右子树同理否则输出$-1$即可。
这里要求最小值所以优先找左子树即可。
这样做的单次查询复杂度是$O(k log{n})$的,$k$很小,肯定能过。
#include <iostream> #include <cstdio> using namespace std; const int N = 300010; struct Segment{ int lson, rson, val; }tr[N * 30]; int tot; int n, m; int a[N], rt[N]; void ins(int &cur, int pre, int l, int r, int pos, int v) { cur = ++tot; tr[cur] = tr[pre]; tr[cur].val += v; if (l == r) return; int mid = (l + r) >> 1; if (pos <= mid) ins(tr[cur].lson, tr[pre].lson, l, mid, pos, v); else ins(tr[cur].rson, tr[pre].rson, mid + 1, r, pos, v); } bool ask(int x, int y, int l, int r, int k) { if (l == r) { printf("%d ", l); return true; } int mid = (l + r) >> 1; if (tr[tr[y].lson].val - tr[tr[x].lson].val > k) { if (ask(tr[x].lson, tr[y].lson, l, mid, k)) return true; } if (tr[tr[y].rson].val - tr[tr[x].rson].val > k) { if (ask(tr[x].rson, tr[y].rson, mid + 1, r, k)) return true; } return false; } 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], 1); } while (m--) { int l, r, k; scanf("%d%d%d", &l, &r, &k); k = (r - l + 1) / k; if (!ask(rt[l - 1], rt[r], 1, n, k)) puts("-1"); } return 0; }