P6779 [Ynoi2009] rla1rmdq

分块。

边权非负,若一个点所处位置已被遍历过,那么这个点在块内无意义,故每个块可均摊 O(n)\mathcal O(n),总 O(nn)\mathcal O(n\sqrt n)

发现散块修改会将原先无意义的点标为有意义的,考虑对块重构即可,单次根号,涉及到求点在树上的 kk 级祖先,重剖即可,分析得不影响复杂度,感性理解往上跳就把这条链删了。

空间的话用 bitset或离线做到线性空间即可。

总时间复杂度 O(nn)\mathcal O(n\sqrt n)

#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;
}
posted @ 2022-09-29 14:02  蒟蒻orz  阅读(10)  评论(0)    收藏  举报  来源