异常欢乐的并查集。馒头染色法。均摊O(n)的时间。


离线,先把每个染色操作会染黑哪些边算出来,把黑色子节点并到白色父节点里。


然后倒着处理,询问就直接用并查集问白色子节点顶上的黑色父节点最近是谁。染色操作再染回来。


#include <cstdio>

#include <cctype>

#include <cstring>

#include <algorithm>


using namespace std;


struct edge {

int t, i;

edge *next;

};

struct query {

int t, v, ans;

int *b;

};


int _d_;

#define readInt(_x_) { \

int& _s_ = _x_; \

_s_ = 0; \

while (!isdigit(_d_ = getchar())); \

while ((_s_ = _s_ * 10 + _d_ - 48), isdigit(_d_ = getchar())); \

}


const int maxn = 1000009;


int n, m, d[maxn], fa[maxn], v[maxn], c[maxn], r[maxn];

int i_buf[maxn], *tib;

query q[maxn];

edge *head[maxn], *ep;


inline void addEdge(int u, int v, int w) {

ep-> t = v;

ep-> i = w;

ep-> next = head[u];

head[u] = ep ++;

}


void buildTree() {

static int q[maxn];

int hd = 0, tl = 1;

memset(d, 0, sizeof(d));

memset(c, 0, sizeof(c));

d[1] = 1;

fa[1] = 0;

fa[0] = 0;

r[0] = 0;

v[0] = 0;

v[1] = 0;

q[hd] = 1;

while (hd < tl) {

int p = q[hd ++];

for (edge* e = head[p]; e; e = e-> next)

if (!d[e-> t]) {

d[e-> t] = d[p] + 1;

fa[e-> t] = p;

v[e-> t] = e-> i;

q[tl ++] = e-> t;

}

}

}


int getRoot(int x) {

int p, q;

for (p = x; r[p] ^ p; p = r[p]);

for (; x ^ p; q = r[x], r[x] = p, x = q);

return p;

}


int lca(int u, int v, int* a) {

int t = 0;

u = getRoot(u);

v = getRoot(v);

while (u ^ v) {

if (d[u] > d[v]) {

a[t ++] = u;

c[u] = 1;

r[u] = getRoot(fa[u]);

u = r[u];

}

else {

a[t ++] = v;

c[v] = 1;

r[v] = getRoot(fa[v]);

v = r[v];

}

}

return t;

}


int main() {

#ifndef ONLINE_JUDGE

freopen("in.txt", "r", stdin);

#endif


readInt(n);

readInt(m);

memset(head, 0, sizeof(head));

ep = new edge[n * 2];

for (int i = 1; i < n; ++ i) {

int u, v;

readInt(u);

readInt(v);

addEdge(u, v, i);

addEdge(v, u, i);

}

buildTree();

tib = i_buf;

for (int i = 1; i <= n; ++ i)

r[i] = i;

for (int i = 0; i < m; ++ i) {

readInt(q[i]. t);

if (q[i]. t == 1) {

readInt(q[i]. v);

}

else {

int u, v;

readInt(u);

readInt(v);

q[i]. b = tib;

q[i]. v = lca(u, v, q[i]. b);

tib += q[i]. v;

}

}

for (int i = 1; i <= n; ++ i)

if (c[i])

r[i] = i;

else

r[i] = fa[i];

for (int i = m - 1; i >= 0; -- i)

if (q[i]. t == 1)

q[i]. ans = v[getRoot(q[i]. v)];

else {

for (int j = 0; j < q[i]. v; ++ j) {

int p = q[i]. b[j];

r[p] = getRoot(fa[p]);

c[p] = 0;

}

}

for (int i = 0; i < m; ++ i)

if (q[i]. t == 1)

printf("%d\n", q[i]. ans);

}