P6779 [Ynoi2009] rla1rmdq
分块。
边权非负,若一个点所处位置已被遍历过,那么这个点在块内无意义,故每个块可均摊 ,总 。
发现散块修改会将原先无意义的点标为有意义的,考虑对块重构即可,单次根号,涉及到求点在树上的 级祖先,重剖即可,分析得不影响复杂度,感性理解往上跳就把这条链删了。
空间的话用 bitset
或离线做到线性空间即可。
总时间复杂度 。
#include <bits/stdc++.h>
using namespace std;
namespace Fread
{
const int SIZE = 1 << 23;
char buf[SIZE], *S, *T;
inline char getchar()
{
if (S == T)
{
T = (S = buf) + fread(buf, 1, SIZE, stdin);
if (S == T)
return '\n';
}
return *S++;
}
}
namespace Fwrite
{
const int SIZE = 1 << 23;
char buf[SIZE], *S = buf, *T = buf + SIZE;
inline void flush()
{
fwrite(buf, 1, S - buf, stdout);
S = buf;
}
inline void putchar(char c)
{
*S++ = c;
if (S == T)
flush();
}
struct NTR
{
~NTR()
{
flush();
}
} ztr;
}
#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endif
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = x * 10 + c - '0', c = getchar();
return x * f;
}
typedef long long ll;
inline void write(ll x)
{
if(x < 0)
{
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
const int _ = 2e5 + 10, sq = 607;
int n, q, rt;
int tot, head[_], to[_ << 1], nxt[_ << 1], w[_ << 1];
int dfn[_], idfn[_], tim, fa[_], siz[_], hson[_], top[_], d[_];
int a[_], bl[_], br[_], bel[_], que[_], Tp, tag, blk, val[_];
ll dep[_], ans[_];
bool vis[_], inq[_];
inline void add(int u, int v, int d) {
to[++tot] = v, nxt[tot] = head[u], w[tot] = d, head[u] = tot;
}
struct Query {
int op, l, r;
} qur[_];
void dfs1(int u, int D = 1) {
d[u] = D, siz[u] = 1;
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (siz[v]) continue;
dep[v] = dep[u] + w[i];
fa[v] = u;
dfs1(v, D + 1);
siz[u] += siz[v];
if (siz[hson[u]] < siz[v]) hson[u] = v;
}
}
void dfs2(int u, int tf) {
top[u] = tf;
dfn[u] = ++tim, idfn[tim] = u;
if (hson[u]) dfs2(hson[u], tf);
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (top[v]) continue;
dfs2(v, v);
}
}
inline int kth(int u, int k) {
if (k >= d[u]) return rt;
while (k > dfn[u] - dfn[top[u]]) {
k -= dfn[u] - dfn[top[u]] + 1;
u = fa[top[u]];
}
return idfn[dfn[u] - k];
}
inline void solve(int L, int R) {
for (int i = 1; i <= n; ++i) vis[i] = inq[i] = 0, val[i] = que[i] = 0;
ll bas = 1e18;
tag = 0, Tp = 0;
for (int i = L; i <= R; ++i)
if (!vis[a[i]]) {
vis[a[i]] = inq[i] = 1;
que[++Tp] = i;
bas = min(bas, dep[a[i]]);
}
for (int i = 1; i <= q; ++i) {
int op = qur[i].op, l = max(qur[i].l, L), r = min(qur[i].r, R);
if (l > r) continue;
if (op == 1) {
if (L == l && r == R) {
int tmp = Tp;
tag++, Tp = 0;
for (int i = 1; i <= tmp; ++i) {
val[que[i]]++;
if (vis[a[que[i]] = fa[a[que[i]]]]) inq[que[i]] = 0;
else {
que[++Tp] = que[i];
bas = min(bas, dep[a[que[i]]]);
vis[a[que[i]]] = 1;
}
}
} else {
for (int i = l; i <= r; ++i) {
if (!vis[a[i] = kth(a[i], tag - val[i] + 1)]) {
bas = min(bas, dep[a[i]]);
if (!inq[i]) {
que[++Tp] = i;
vis[a[i]] = inq[i] = 1;
}
}
val[i] = tag;
}
}
} else {
if (L == l && r == R) ans[i] = min(ans[i], bas);
else {
for (int j = l; j <= r; ++j) {
ans[i] = min(ans[i], dep[a[j] = kth(a[j], tag - val[j])]);
val[j] = tag;
}
}
}
}
}
signed main() {
n = read(), q = read(), rt = read();
for (int i = 1, u, v, d; i < n; ++i) {
u = read(), v = read(), d = read();
add(u, v, d), add(v, u, d);
}
dfs1(rt), dfs2(rt, rt);
for (int i = 1; i <= n; ++i) a[i] = read();
for (int i = 1; i <= q; ++i) {
qur[i].op = read(), qur[i].l = read(), qur[i].r = read();
ans[i] = 1e18;
}
blk = (n - 1) / sq + 1;
for (int i = 1; i <= blk; ++i) {
bl[i] = br[i - 1] + 1, br[i] = min(i * sq, n);
for (int j = bl[i]; j <= br[i]; ++j) bel[j] = i;
}
for (int i = 1; i <= blk; ++i) solve(bl[i], br[i]);
for (int i = 1; i <= q; ++i)
if (qur[i].op == 2) write(ans[i]), putchar('\n');
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18121957