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;
}