题目链接:https://loj.ac/problem/2001
关键在于操作1,发现是一个LCT的Access操作,每次Access,将断掉的儿子所在的子树答案全部+1,将连接到这个节点的子树答案全部-1,然后我们可以利用dfs序来进行更新,同时用线段树维护,操作2为线段树上的单点查询,操作3为线段树上的区间查询。
代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000+5;
struct Edge
{
int to,next;
}edge[MAXN*2];
int head[MAXN],tot,in[MAXN],out[MAXN],tag;
void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void init()
{
tot=0;tag=0;
memset(head,-1,sizeof(head));
}
struct seg
{
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
int mx[MAXN<<2],lazy[MAXN<<2];
inline void push_up(int rt)
{
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
inline void push_down(int rt)
{
if(lazy[rt])
{
mx[rt<<1]+=lazy[rt];
lazy[rt<<1]+=lazy[rt];
mx[rt<<1|1]+=lazy[rt];
lazy[rt<<1|1]+=lazy[rt];
lazy[rt]=0;
}
}
void update(int L,int R,int val,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
lazy[rt]+=val;
mx[rt]+=val;
return ;
}
int mid=(l+r)>>1;
push_down(rt);
if(mid>=L)
update(L,R,val,lson);
if(mid<R)
update(L,R,val,rson);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return mx[rt];
}
int mid=(l+r)>>1;
int ret=0;
push_down(rt);
if(L<=mid)
{
ret=max(ret,query(L,R,lson));
}
if(mid<R)
{
ret=max(ret,query(L,R,rson));
}
return ret;
}
}T;
namespace lca
{
const int DEG=20;
int fa[MAXN][DEG];//fa[i][j]表示结点i的第2^j个祖先
int deg[MAXN];//深度数组
void BFS(int root)
{
queue<int>que;
deg[root]=0;
fa[root][0]=root;
que.push(root);
while(!que.empty())
{
int tmp=que.front();
que.pop();
for(int i=1;i<DEG;i++)
fa[tmp][i]=fa[fa[tmp][i-1]][i-1];
for(int i=head[tmp];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[tmp][0])continue;
deg[v]=deg[tmp]+1;
fa[v][0]=tmp;
que.push(v);
}
}
}
int LCA(int u,int v)
{
if(deg[u]>deg[v])swap(u,v);
int hu=deg[u],hv=deg[v];
int tu=u,tv=v;
for(int det=hv-hu,i=0;det;det>>=1,i++)
if(det&1)
tv=fa[tv][i];
if(tu==tv)return tu;
for(int i=DEG-1;i>=0;i--)
{
if(fa[tu][i]==fa[tv][i])
continue;
tu=fa[tu][i];
tv=fa[tv][i];
}
return fa[tu][0];
}
}
int n,m;
namespace LCT
{
int ch[MAXN][2],pre[MAXN];
bool rt[MAXN];
void Rotate(int x)
{
int y=pre[x],kind=ch[y][1]==x;
ch[y][kind]=ch[x][!kind];
pre[ch[y][kind]]=y;
pre[x]=pre[y];
pre[y]=x;
ch[x][!kind]=y;
if(rt[y])
rt[y]=false,rt[x]=true;
else
ch[pre[x]][ch[pre[x]][1]==y]=x;
}
void Splay(int r)
{
while(!rt[r])
{
int f=pre[r],ff=pre[f];
if(rt[f])
Rotate(r);
else if((ch[ff][1]==f)==(ch[f][1]==r))
Rotate(f),Rotate(r);
else
Rotate(r),Rotate(r);
}
}
int find(int x)
{
while(ch[x][0])
{
x=ch[x][0];
}
return x;
}
int Access(int x)
{
int y=0;
for(;x;x=pre[y=x])
{
Splay(x);
int p;
if(ch[x][1])
{
p=find(ch[x][1]);
T.update(in[p],out[p],1,1,n,1);
}
if(y)
{
p=find(y);
T.update(in[p],out[p],-1,1,n,1);
}
rt[ch[x][1]]=true,rt[ch[x][1]=y]=false;
}
return y;
}
void init(int n)
{
for(int i=0;i<=n;i++)
{
rt[i]=true;
ch[i][0]=ch[i][1]=0;
pre[i]=0;
}
}
}
void dfs(int u)
{
in[u]=++tag;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(LCT::pre[v]!=0)
continue;
LCT::pre[v]=u;
dfs(v);
}
out[u]=tag;
T.update(in[u],out[u],1,1,n,1);
}
int main()
{
//freopen("paint1.in","r",stdin);
//freopen("out.out","w",stdout);
init();
scanf("%d%d",&n,&m);
LCT::init(n);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
LCT::pre[1]=-1;
dfs(1);
LCT::pre[1]=0;
lca::BFS(1);
//cerr<<clock()<<endl;
while(m--)
{
int op,x,y;
scanf("%d",&op);
if(op==1)
{
scanf("%d",&x);
LCT::Access(x);
}
if(op==2)
{
scanf("%d%d",&x,&y);
int p=lca::LCA(x,y);
int a,b,c;
a=T.query(in[x],in[x],1,n,1);
b=T.query(in[y],in[y],1,n,1);
c=T.query(in[p],in[p],1,n,1);
printf("%d\n",a+b-2*c+1);
}
if(op==3)
{
scanf("%d",&x);
//printf("%d %d\n",in[x],out[x]);
//printf("%d\n",T.mx[1]);
printf("%d\n",T.query(in[x],out[x],1,n,1));
}
}
return 0;
}