P3712 少女与战车 题解

这题跟由乃打扑克的唯一区别就是这题不会放错解过了吧……

求出 DFS 序,问题变为区间加区间 k 小值。

考虑分块,维护每个块排序的结果,

修改时散块归并,整块打标记,

查询时先把散块归并起来,然后二分答案,

check 时散块在归并出的数组上二分,整块在其排序的结果上二分,

设块长为 $B$,总复杂度单次 $O(B+\log n(\log B+\dfrac nB\log B))$,

取 $B=\sqrt n\log n$ 即可做到单次 $O(\sqrt n\log n)$。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct E
{
    int v, w, t;
} e[100050];
int n, q, k, u, c, _, l[350], r[350], z[350], a[100050], w[100050], b[100050], t[100050], f[100050], h[100050], d[100050], s[100050];
void A(int u, int v, int w) { e[++c] = {v, w, h[u]}, h[u] = c; }
bool C(int x, int y) { return a[x] < a[y]; }
bool C1(int x, int y) { return a[x] < y; }
void D(int u, int k)
{
    d[u] = ++_;
    s[u] = 1;
    for (int i = h[u], v; i; i = e[i].t)
        w[v = e[i].v] = w[u] + e[i].w, D(v, u), s[u] += s[v];
}
int Q(int x, int y, int k)
{
    int p = lower_bound(f + 1, f + u + 1, k) - f - 1;
    for (int i = t[x] + 1; i < t[y]; ++i)
    {
        if (a[b[l[i]]] + z[i] >= k)
            continue;
        if (a[b[r[i]]] + z[i] < k)
        {
            p += r[i] - l[i] + 1;
            continue;
        }
        p += lower_bound(b + l[i], b + r[i] + 1, k - z[i], C1) - b - l[i];
    }
    return p;
}
int main()
{
    scanf("%d%d%*d", &n, &q);
    k = 3000;
    for (int i = 2, x, w; i <= n; ++i)
        scanf("%d%d", &x, &w), A(x, i, w);
    D(1, 0);
    for (int i = 1; i <= n; ++i)
        a[d[i]] = w[i];
    for (int i = 1; i <= n; ++i)
        b[i] = i, t[i] = (i - 1) / k + 1;
    for (int i = t[1]; i <= t[n]; ++i)
        l[i] = (i - 1) * k + 1, r[i] = min(l[i] + k - 1, n);
    for (int i = t[1]; i <= t[n]; ++i)
        sort(b + l[i], b + r[i] + 1, C);
    for (int i = 0, o, x, y, k, L, R, M; i < q; ++i)
    {
        scanf("%d%d%d", &o, &x, &k);
        y = d[x] + s[x] - 1, x = d[x];
        if (!(o & 1))
            if (t[x] == t[y])
            {
                for (int i = x; i <= y; ++i)
                    a[i] += k;
                int i = l[t[x]], j = l[t[x]];
                while (i <= r[t[x]] && b[i] >= x && b[i] <= y)
                    ++i;
                while (j <= r[t[x]] && (b[j] < x || b[j] > y))
                    ++j;
                u = 0;
                while (i <= r[t[x]] || j <= r[t[x]])
                {
                    if (j > r[t[x]])
                    {
                        f[++u] = b[i++];
                        while (i <= r[t[x]] && b[i] >= x && b[i] <= y)
                            ++i;
                    }
                    else if (i > r[t[x]])
                    {
                        f[++u] = b[j++];
                        while (j <= r[t[x]] && (b[j] < x || b[j] > y))
                            ++j;
                    }
                    else if (a[b[i]] <= a[b[j]])
                    {
                        f[++u] = b[i++];
                        while (i <= r[t[x]] && b[i] >= x && b[i] <= y)
                            ++i;
                    }
                    else
                    {
                        f[++u] = b[j++];
                        while (j <= r[t[x]] && (b[j] < x || b[j] > y))
                            ++j;
                    }
                }
                for (int i = 1; i <= u; ++i)
                    b[l[t[x]] + i - 1] = f[i];
            }
            else
            {
                for (int i = x; i <= r[t[x]]; ++i)
                    a[i] += k;
                for (int i = l[t[y]]; i <= y; ++i)
                    a[i] += k;
                for (int i = t[x] + 1; i < t[y]; ++i)
                    z[i] += k;
                int i = l[t[x]], j = l[t[x]];
                while (i <= r[t[x]] && b[i] >= x)
                    ++i;
                while (j <= r[t[x]] && b[j] < x)
                    ++j;
                u = 0;
                while (i <= r[t[x]] || j <= r[t[x]])
                {
                    if (j > r[t[x]])
                    {
                        f[++u] = b[i++];
                        while (i <= r[t[x]] && b[i] >= x)
                            ++i;
                    }
                    else if (i > r[t[x]])
                    {
                        f[++u] = b[j++];
                        while (j <= r[t[x]] && b[j] < x)
                            ++j;
                    }
                    else if (a[b[i]] <= a[b[j]])
                    {
                        f[++u] = b[i++];
                        while (i <= r[t[x]] && b[i] >= x)
                            ++i;
                    }
                    else
                    {
                        f[++u] = b[j++];
                        while (j <= r[t[x]] && b[j] < x)
                            ++j;
                    }
                }
                for (int i = 1; i <= u; ++i)
                    b[l[t[x]] + i - 1] = f[i];
                i = l[t[y]], j = l[t[y]];
                while (i <= r[t[y]] && b[i] <= y)
                    ++i;
                while (j <= r[t[y]] && b[j] > y)
                    ++j;
                u = 0;
                while (i <= r[t[y]] || j <= r[t[y]])
                {
                    if (j > r[t[y]])
                    {
                        f[++u] = b[i++];
                        while (i <= r[t[y]] && b[i] <= y)
                            ++i;
                    }
                    else if (i > r[t[y]])
                    {
                        f[++u] = b[j++];
                        while (j <= r[t[y]] && b[j] > y)
                            ++j;
                    }
                    else if (a[b[i]] <= a[b[j]])
                    {
                        f[++u] = b[i++];
                        while (i <= r[t[y]] && b[i] <= y)
                            ++i;
                    }
                    else
                    {
                        f[++u] = b[j++];
                        while (j <= r[t[y]] && b[j] > y)
                            ++j;
                    }
                }
                for (int i = 1; i <= u; ++i)
                    b[l[t[y]] + i - 1] = f[i];
            }
        else
        {
            if (y - x + 1 < k)
            {
                puts("-1");
                continue;
            }
            if (t[x] == t[y])
            {
                u = 0;
                for (int i = l[t[x]]; i <= r[t[x]]; ++i)
                    if (b[i] >= x && b[i] <= y)
                        f[++u] = a[b[i]] + z[t[x]];
                printf("%d\n", f[k]);
            }
            else
            {
                L = 2e9;
                R = -2e9;
                for (int i = x; i <= r[t[x]]; ++i)
                    L = min(L, a[i] + z[t[i]]), R = max(R, a[i] + z[t[i]]);
                for (int i = l[t[y]]; i <= y; ++i)
                    L = min(L, a[i] + z[t[i]]), R = max(R, a[i] + z[t[i]]);
                for (int i = t[x] + 1; i < t[y]; ++i)
                    L = min(L, a[b[l[i]]] + z[i]), R = max(R, a[b[r[i]]] + z[i]);
                int i = l[t[x]], j = l[t[y]];
                while (i <= r[t[x]] && b[i] < x)
                    ++i;
                while (j <= r[t[y]] && b[j] > y)
                    ++j;
                u = 0;
                while (i <= r[t[x]] || j <= r[t[y]])
                {
                    if (j > r[t[y]])
                    {
                        f[++u] = a[b[i++]] + z[t[x]];
                        while (i <= r[t[x]] && b[i] < x)
                            ++i;
                    }
                    else if (i > r[t[x]])
                    {
                        f[++u] = a[b[j++]] + z[t[y]];
                        while (j <= r[t[y]] && b[j] > y)
                            ++j;
                    }
                    else if (a[b[i]] + z[t[x]] <= a[b[j]] + z[t[y]])
                    {
                        f[++u] = a[b[i++]] + z[t[x]];
                        while (i <= r[t[x]] && b[i] < x)
                            ++i;
                    }
                    else
                    {
                        f[++u] = a[b[j++]] + z[t[y]];
                        while (j <= r[t[y]] && b[j] > y)
                            ++j;
                    }
                }
                while (L <= R)
                    if (Q(x, y, M = L + (R - L >> 1)) < k)
                        L = M + 1;
                    else
                        R = M - 1;
                printf("%d\n", R);
            }
        }
    }
    return 0;
}
posted @ 2024-02-20 21:40  5k_sync_closer  阅读(32)  评论(1编辑  收藏  举报  来源