Hello, PastePlz!

Paste Time: 2023-09-11 22:09:12.516134222 +08:00:00
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
	int t = 0;
	char v = getchar();
	while (v < '0')
		v = getchar();
	while (v >= '0')
		t = (t << 3) + (t << 1) + v - 48, v = getchar();
	return t;
}
int n, m, fa[700002], Siz[700002], bl[100002], N[500002], c[100002], V[500002], col[700002], rt[100002], ls[15000002], rs[15000002], siz[15000002], pos[15000002], tot, num, A[100002], B[100002], C[100002], O[500002], X[500002], Y[500002], Z[500002];
vector<int> G[100002], W[100002], S[100002], Q[500002];
inline void add(int x, int y, int z) { G[x].push_back(y), W[x].push_back(z); }
inline int root(int x) { return x == fa[x] ? x : fa[x] = root(fa[x]); }
inline void ins(int &p, int l, int r, int x, int y)
{
	if (!p)
		p = ++tot;
	siz[p] += Siz[y];//siz:线段树子树和 Siz:并查集集合大小
	if (l == r)
	{
		if (!pos[p])
			pos[p] = ++num, fa[num] = num, col[num] = l;//pos :线段树叶子结点对应集合编号
		fa[y] = pos[p], Siz[pos[p]] += Siz[y];
		return;
	}
	int mid = l + r >> 1;
	if (x <= mid)
		ins(ls[p], l, mid, x, y);
	else
		ins(rs[p], mid + 1, r, x, y);
}
vector<int> AA;
inline void Get(int p, int l, int r, int x, int y)
{
	if (!siz[p])
		return;
	if (l == r)
	{
		AA.push_back(pos[p]);
		pos[p] = siz[p] = 0;
		return;
	}
	int mid = l + r >> 1;
	if (x <= mid)
		Get(ls[p], l, mid, x, y);
	if (y > mid)
		Get(rs[p], mid + 1, r, x, y);
	siz[p] = siz[ls[p]] + siz[rs[p]];
}
inline int ask(int p, int l, int r, int x, int y)
{
	if (!siz[p] || (l >= x && r <= y))
		return siz[p];
	int mid = l + r >> 1, s = 0;
	if (x <= mid)
		s += ask(ls[p], l, mid, x, y);
	if (y > mid)
		s += ask(rs[p], mid + 1, r, x, y);
	return s;
}
inline void chk(int p, int l, int r, int x)
{
	if (l == r)
	{
		siz[p] = Siz[pos[p]];
		return;
	}
	int mid = l + r >> 1;
	if (x <= mid)
		chk(ls[p], l, mid, x);
	else
		chk(rs[p], mid + 1, r, x);
	siz[p] = siz[ls[p]] + siz[rs[p]];
}
inline void dfs(int x, int y)
{
	for (int i = 0; i < G[x].size(); ++i)
		if (G[x][i] ^ y)
		{
			if (C[W[x][i]] == m + 1)
				bl[G[x][i]] = bl[x];
			else
				bl[G[x][i]] = G[x][i];//G:邻接表,w:边的初始id,bl:始终没有拆开的连通块的代表元
			dfs(G[x][i], x);
		}
}
inline int Ask(int x) { return col[root(x)]; }
int main()
{
	n = read(), m = read();
	for (int i = 1; i <= n; ++i)
		c[i] = read();
	for (int i = 1; i < n; ++i)
		A[i] = read(), B[i] = read(), C[i] = m + 1, add(A[i], B[i], i), add(B[i], A[i], i);//C:删除时间
	for (int i = 1; i <= m; ++i)
	{
		O[i] = read();
		if (O[i] == 1)
			X[i] = read(), C[X[i]] = i;
		else if (O[i] == 2)
			V[i] = read(), X[i] = read(), Y[i] = read(), Z[i] = read();
		else
			V[i] = read(), X[i] = read(), Y[i] = read();
	}
	bl[1] = 1, dfs(1, 1), num = n;
	for (int i = 1; i <= n; ++i)
		S[bl[i]].push_back(i), Siz[i] = 1, fa[i] = i, ins(rt[1], 1, n, c[i], i);
	for (int i = m; i; --i)
		if (O[i] == 1)
		{
			int x = bl[A[X[i]]], y = bl[B[X[i]]];
			if (S[x].size() > S[y].size())
				swap(x, y);
			N[i] = x;
			for (auto z : S[x])
				S[y].push_back(z), Q[i].push_back(z), bl[z] = y;
		}
	for (int i = 1; i <= n; ++i)
		bl[i] = 1;
	for (int i = 1; i <= m; ++i)
	{
		if (O[i] == 1)
		{
			for (auto z : Q[i])
			{
				--Siz[root(z)], chk(rt[bl[z]], 1, n, c[z] = Ask(z));
				bl[z] = N[i], ins(rt[bl[z]], 1, n, c[z], z);//复杂度瓶颈在这里
			}
		}
		else if (O[i] == 2)
		{
			AA.clear(), Get(rt[bl[V[i]]], 1, n, X[i], Y[i]);//操作2每次暴力都以一个log的代价消灭了一个结点,然后生成一个节点,操作1只会生成一个节点,总共是不超过O(nlogn)的。
			++num, fa[num] = num;
			for (auto z : AA)
				fa[z] = num, Siz[num] += Siz[z];
			ins(rt[bl[V[i]]], 1, n, Z[i], num);
		}
		else
			printf("%d\n", ask(rt[bl[V[i]]], 1, n, X[i], Y[i]));
	}
}