Description
Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作
Sample Input
5 6
1 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5
Sample Output
3
4
2
2
一开始易得一个想法,s[x]表示根到x不一样的颜色数。
对于第二个询问,既然他每次染的颜色都是不一样的,那你就可以直接用s[x]+s[y]-2*s[lca]+1即可。
对于第三个询问,直接输出max。
然后就要考虑修改,其实也比较容易想到,对于一个点往上走,一遇到不同的颜色,就修改,全部修改一遍时间复杂度可以均摊到mlogn。
那么该怎么搞呢。。。
一开始的想法是一个并查集,但想想就很fake。。。
膜了题解,好吧,是个LCT
你每次然一段色其实就相当于access一下,每次一条虚边相连就说明上下两段颜色不同,然后你access上去时修改一下即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int _max(int x, int y) {return x > y ? x : y;}
inline int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
struct tnode {
int son[2], f;
} t[110000];
struct node {
int l, r, lc, rc, c, lazy;
} tr[210000]; int cnt;
int id, ll[110000], rr[110000];
struct edge {
int x, y, next;
} e[210000]; int len, last[110000];
int dep[110000], fa[20][110000];
void ins(int x, int y) {
e[++len].x = x; e[len].y = y;
e[len].next = last[x]; last[x] = len;
}
bool hh(int x) {
int f = t[x].f;
if(f == 0 || (t[f].son[0] != x && t[f].son[1] != x)) return 0;
return 1;
}
void rotate(int x, int fx) {
int f = t[x].f, ff = t[f].f;
int r, R;
r = t[x].son[fx], R = f;
t[R].son[1 ^ fx] = r;
if(r) t[r].f = R;
r = x, R = ff;
if(t[R].son[0] == f) t[R].son[0] = r; else if(t[R].son[1] == f) t[R].son[1] = r;
t[r].f = R;
r = f, R = x;
t[R].son[fx] = r;
t[r].f = R;
}
void splay(int x) {
while(hh(x)) {
int f = t[x].f, ff = t[f].f;
if(!hh(f)) {
if(t[f].son[0] == x) rotate(x, 1);
else if(t[f].son[1] == x) rotate(x, 0);
}
else if(t[f].son[0] == x && t[ff].son[0] == f) rotate(f, 1), rotate(x, 1);
else if(t[f].son[0] == x && t[ff].son[1] == f) rotate(x, 1), rotate(x, 0);
else if(t[f].son[1] == x && t[ff].son[1] == f) rotate(f, 0), rotate(x, 0);
else if(t[f].son[1] == x && t[ff].son[0] == f) rotate(x, 0), rotate(x, 1);
}
}
void bt(int l, int r) {
int now = ++cnt;
tr[now].l = l, tr[now].r = r;
tr[now].lc = tr[now].rc = -1;
tr[now].c = 0;
if(l < r) {
int mid = (l + r) / 2;
tr[now].lc = cnt + 1; bt(l, mid);
tr[now].rc = cnt + 1; bt(mid + 1, r);
}
}
void Lazy(int now) {
if(!tr[now].lazy) return ;
int lc = tr[now].lc, rc = tr[now].rc;
tr[lc].c += tr[now].lazy, tr[rc].c += tr[now].lazy;
tr[lc].lazy += tr[now].lazy, tr[rc].lazy += tr[now].lazy;
tr[now].lazy = 0;
}
void change(int now, int l, int r, int c) {
if(tr[now].l == l && tr[now].r == r) {
tr[now].c += c;
tr[now].lazy += c;
return ;
} Lazy(now);
int lc = tr[now].lc, rc = tr[now].rc;
int mid = (tr[now].l + tr[now].r) / 2;
if(r <= mid) change(lc, l, r, c);
else if(l > mid) change(rc, l, r, c);
else change(lc, l, mid, c), change(rc, mid + 1, r, c);
tr[now].c = _max(tr[lc].c, tr[rc].c);
}
int findmax(int now, int l, int r) {
if(tr[now].l == l && tr[now].r == r) return tr[now].c;
Lazy(now);
int lc = tr[now].lc, rc = tr[now].rc;
int mid = (tr[now].l + tr[now].r) / 2;
if(r <= mid) return findmax(lc, l, r);
else if(l > mid) return findmax(rc, l, r);
else return _max(findmax(lc, l, mid), findmax(rc, mid + 1, r));
}
int getrt(int x) {
while(t[x].son[0]) x = t[x].son[0];
return x;
}
void access(int x) {
int y = 0;
while(x) {
splay(x);
if(t[x].son[1]) {
int hh = getrt(t[x].son[1]);
change(1, ll[hh], rr[hh], 1);
} t[x].son[1] = y;
if(y) {
t[y].f = x;
int hh = getrt(y);
change(1, ll[hh], rr[hh], -1);
} y = x; x = t[x].f;
}
}
void dfs(int x) {
t[x].f = fa[0][x];
for(int i = 1; (1 << i) <= dep[x]; i++) fa[i][x] = fa[i - 1][fa[i - 1][x]];
ll[x] = ++id;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(y != fa[0][x]) fa[0][y] = x, dep[y] = dep[x] + 1, dfs(y);
} rr[x] = id;
}
int LCA(int x, int y) {
if(dep[x] > dep[y]) swap(x, y);
for(int i = 18; i >= 0; i--) if(dep[y] - dep[x] >= (1 << i)){
y = fa[i][y];
} if(x == y) return x;
for(int i = 18; i >= 0; i--) if(fa[i][x] != fa[i][y]){
x = fa[i][x], y = fa[i][y];
} return fa[0][x];
}
int main() {
int n = read(), m = read();
for(int i = 1; i < n; i++) {
int x = read(), y = read();
ins(x, y), ins(y, x);
} dep[1] = 0; dfs(1); bt(1, n);
for(int i = 1; i <= n; i++) change(1, ll[i], ll[i], dep[i]);
for(int i = 1; i <= m; i++) {
int opt = read(), x = read(), y;
if(opt == 1) access(x);
else if(opt == 2) {
y = read();
int lca = LCA(x, y);
int a = findmax(1, ll[x], ll[x]), b = findmax(1, ll[y], ll[y]), c = findmax(1, ll[lca], ll[lca]);
printf("%d\n", a + b - c * 2 + 1);
} else printf("%d\n", findmax(1, ll[x], rr[x]) + 1);
}
return 0;
}