Description
Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作
Input
第一行两个数n,m。
接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
接下来m行,表示操作,格式见题目描述
1<=n,m<=100000
Output
每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值
如果是3操作,输出一个数表示权值的最大值
题解:
lct维护第一个操作,每断开一次相当于子树+1,接上子树-1
然后线段树维护dfs统计答案
key:利用lct,access的特殊性质来维护
注意:子树修改时要找链上深度最浅的点,而不是当前splay的根
链剖lca忘更新sz,血T
第一次用namespace打代码好写好调,以后多写类似的版
#include<bits/stdc++.h>
using namespace std;
#define maxn 100020
struct node{
int next,to;
}e[maxn * 2];
int head[maxn],cnt,n,m,top[maxn],sz[maxn],dth[maxn],son[maxn],fa[maxn],dfstime,a[maxn],l[maxn],r[maxn];
struct seg{
#define lson x << 1,l,mid
#define rson x << 1|1,mid+1,r
#define N 400020
int mx[N],add[N];
inline void update(int x){
mx[x] = max(mx[x << 1],mx[x << 1|1]);
}
void build(int x,int l,int r){
if ( l == r ){ mx[x] = dth[a[l]]; return; }
register int mid = (l + r) >> 1;
build(lson) , build(rson);
update(x);
}
inline void Add(int x,int d){
add[x] += d , mx[x] += d;
}
inline void pushdown(int x){
if ( add[x] != 0 ){
Add(x << 1,add[x]);
Add(x << 1|1,add[x]);
add[x] = 0;
}
}
void modify(int x,int l,int r,int ls,int rs,int d){
if ( ls <= l && rs >= r ){ Add(x,d); return; }
register int mid = (l + r) >> 1;
pushdown(x);
if ( ls <= mid ) modify(lson,ls,rs,d);
if ( rs > mid ) modify(rson,ls,rs,d);
update(x);
}
int query(int x,int l,int r,int id){
if ( l == r ) return mx[x];
register int mid = (l + r) >> 1;
pushdown(x);
if ( id <= mid ) return query(lson,id);
return query(rson,id);
}
int query(int x,int l,int r,int ls,int rs){
if ( ls <= l && rs >= r ) return mx[x];
register int mid = (l + r) >> 1;int cur = 0;
pushdown(x);
if ( ls <= mid ) cur = query(lson,ls,rs);
if ( rs > mid ) cur = max(cur,query(rson,ls,rs));
return cur;
}
}T;
namespace LCT{
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define N 100020
int fa[N],ch[N][2],sz[N],rev[N]; //树的形态固定,fa[x]初始时应该用树上的fa
int stack_[maxn],tops = -1;
inline void update(int x){
sz[x] = sz[ls(x)] + sz[rs(x)] + 1;
}
inline bool isroot(int x){
return (ls(fa[x]) != x) && (rs(fa[x]) != x);
}
inline void reverse(int x){
if ( !x ) return;
rev[x] ^= 1 , swap(ls(x),rs(x));
}
inline void pushdown(int x){
if ( rev[x] ){
reverse(ls(x));
reverse(rs(x));
rev[x] = 0;
}
}
inline void rotate(int x){
int y = fa[x] , t = rs(y) == x , z = ch[x][1 - t];
fa[x] = fa[y];
if ( !isroot(y) ) ch[fa[y]][rs(fa[y]) == y] = x;
fa[y] = x , ch[x][1 - t] = y;
if ( z ) fa[z] = y;
ch[y][t] = z;
//update(y);
}
inline void splay(int x){
tops = -1;
stack_[++tops] = x;
for (int i = x ; !isroot(i) ; i = fa[i]) stack_[++tops] = fa[i];
while ( ~tops ) pushdown(stack_[tops--]);
pushdown(x);
while ( !isroot(x) ){
int y = fa[x] , z = fa[y];
if ( !isroot(y) && !((ls(z) == y) ^ (ls(y) == x)) ) rotate(y);
else rotate(x);
if ( !isroot(x) ) rotate(x);
}
//update(x);
}
void access(int x){
int t = 0,y = 0;
for (;x;x = fa[x]){
splay(x);
if ( t ){
y = t;
while ( ls(y) ) y = ls(y);
T.modify(1,1,n,l[y],r[y],-1); //要对当前链上深度最小的区间修改,不能直接用splay的根
}
if ( rs(x) ){
y = rs(x);
while ( ls(y) ) y = ls(y); //同理,找深度最小
T.modify(1,1,n,l[y],r[y],1);
}
ch[x][1] = t , t = x; //update(x)
}
}
}
inline void adde(int x,int y){
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
}
void dfs(int x){
sz[x] = 1 , l[x] = ++dfstime , a[dfstime] = x;
for (int i = head[x] ; i ; i = e[i].next){
if ( e[i].to == fa[x] ) continue;
dth[e[i].to] = dth[x] + 1;
fa[e[i].to] = x ;
dfs(e[i].to);
sz[x] += sz[e[i].to];
if ( sz[son[x]] < sz[e[i].to] ) son[x] = e[i].to;
}
r[x] = dfstime;
}
void dfs2(int x){
if ( son[x] ){
top[son[x]] = top[x];
dfs2(son[x]);
}
for (int i = head[x] ; i ; i = e[i].next){
if ( e[i].to == fa[x] || e[i].to == son[x] ) continue;
top[e[i].to] = e[i].to;
dfs2(e[i].to);
}
}
inline int lca(int x,int y){
while ( top[x] != top[y] ){
if ( dth[top[x]] < dth[top[y]] ) swap(x,y);
x = fa[top[x]];
}
if ( dth[x] < dth[y] ) return x;
return y;
}
int main(){
freopen("input.txt","r",stdin);
scanf("%d %d",&n,&m);
for (int i = 1 ; i < n ; i++){
int x,y;
scanf("%d %d",&x,&y);
adde(x,y) , adde(y,x);
}
dth[1] = 1 , dfs(1) , top[1] = 1, dfs2(1);
memcpy(LCT::fa,fa,sizeof(fa));
T.build(1,1,n);
while ( m-- ){
int t,x,y,lca_;
scanf("%d",&t);
if ( t == 1 ){
scanf("%d",&x);
LCT::access(x);
}
else if ( t == 2 ){
scanf("%d %d",&x,&y);
lca_ = lca(x,y);
printf("%d\n",T.query(1,1,n,l[x]) + T.query(1,1,n,l[y]) - 2 * T.query(1,1,n,l[lca_]) + 1);
}
else{
scanf("%d",&x);
printf("%d\n",T.query(1,1,n,l[x],r[x]));
}
// cout<<T.query(1,1,n,l[3])<<endl;
}
return 0;
}