题面
SOL
维护颜色集合? 树上莫队?好像做不了3操作,只有30分。。。
o p 1 op1 op1:
若进行链修改,相当于把 x x x到根路径拼成了一段,一开始点 i i i到根的权值为 d e p [ i ] dep[i] dep[i],相当于每一个点都是独立的一段。那么点到根的权值就是该路径上的 “总段数”。
那我们就用维护每一个点到根的权值。
但是我们还是不能快速处理
o
p
1
op1
op1。思考
L
C
T
LCT
LCT的
a
c
c
e
s
s
access
access,不是把点到根的路径拼成了一个
s
p
l
a
y
splay
splay吗?
所以我们用
L
C
T
LCT
LCT维护
o
p
1
op1
op1的修改,每一
a
c
c
e
s
s
access
access时,会有重儿子被分开,轻儿子被加入,分开就子树
+
1
+1
+1,加入就子树
−
1
-1
−1。
注意这里要再写一个 d f s dfs dfs序上的线段树。因为splay只能维护子树信息,不能修改。
注意, s p l a y splay splay维护的是一段点,如果要找子树的根,需要找到该 s p l a y splay splay中深度最浅的点
o p 2 : op2: op2:
a n s = v a l [ u ] + v a l [ v ] − 2 ∗ v a l [ f a ] + 1 ans=val[u]+val[v]-2*val[fa]+1 ans=val[u]+val[v]−2∗val[fa]+1
o p 3 : op3: op3:
子树求max
复杂度: O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
CODE
//羽毛球打得我手好累,,故代码中变量名从简+各种压行。。
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define cs const
#define db double
#define ri register int
#define gc getchar()
#define in red()
inline int red(){
int num=0,f=1;char c=gc;
for(;!isdigit(c);c=gc)if(c=='-')f=-1;
for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
return num*f;
}
cs int N=1e5+10;
//dfs序 + 欧拉序
int fa[N],siz[N],dep[N],dfn[N],tot=0,st[20][N<<1],Log[N<<1],cnt=0,pos[N],rev[N],n,m;
vector<int> g[N];
void dfs(int u){
dep[u]=dep[fa[u]]+1;siz[u]=1;dfn[u]=++tot;rev[tot]=u;st[0][++cnt]=u;pos[u]=cnt;
for(ri i=g[u].size()-1;i>=0;--i){
int v=g[u][i];
if(v==fa[u])continue;
fa[v]=u;dfs(v);siz[u]+=siz[v];
st[0][++cnt]=u;
}
}
inline int _min(int a,int b){return dep[a]<dep[b] ? a:b;}
inline void init(){
dfs(1);
Log[1]=0;
for(ri i=2;i<=cnt;++i)Log[i]=Log[i>>1]+1;
for(ri i=1;i<=Log[cnt];++i)
for(ri j=1;j+(1<<i)-1<=cnt;++j)
st[i][j]=_min(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
inline int lca(int x,int y){
int fx=min(pos[x],pos[y]),fy=max(pos[x],pos[y]),k=Log[fy-fx+1];
return _min(st[k][fx],st[k][fy-(1<<k)+1]);
}
//线段树
#define lc (p<<1)
#define rc ((p<<1)|1)
int mx[N<<2],tag[N<<2];
inline void PN(int p,int k){mx[p]+=k;tag[p]+=k;}
inline void PD(int p){if(tag[p])PN(lc,tag[p]),PN(rc,tag[p]);tag[p]=0;}
inline void PU(int p){mx[p]=max(mx[lc],mx[rc]);}
inline void up(int p,int l,int r,int ql,int qr,int k){
if(ql<=l&&r<=qr)return PN(p,k);
PD(p);int mid=(l+r)>>1;
if(ql<=mid)up(lc,l,mid,ql,qr,k);if(qr>mid)up(rc,mid+1,r,ql,qr,k);
PU(p);
}
inline int qy(int p,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return mx[p];
PD(p);int mid=(l+r)>>1,res=0;
if(ql<=mid)res=max(res,qy(lc,l,mid,ql,qr));if(qr>mid)res=max(res,qy(rc,mid+1,r,ql,qr));
return res;
}
inline void BD(int p,int l,int r){
if(l==r)return mx[p]=dep[rev[l]],void();
int mid=(l+r)>>1;BD(lc,l,mid);BD(rc,mid+1,r);
PU(p);
}
//LCT
int ch[N][2];
inline int CK(int u){return ch[fa[u]][0]^u&&ch[fa[u]][1]^u? -1 : ch[fa[u]][1]==u; }
inline void rotate(int x){
int y=fa[x],z=fa[y],d=CK(x),d1=CK(y);
if(~d1)ch[z][d1]=x;
fa[x]=z;fa[ch[x][d^1]]=y;ch[y][d]=ch[x][d^1];ch[x][d^1]=y;fa[y]=x;
}
inline void splay(int x){
while(~CK(x)){
if(~CK(fa[x]))rotate(CK(fa[x])^CK(x) ? x : fa[x]);
rotate(x);
}
}
inline int find(int p){return ch[p][0] ? find(ch[p][0]) : p ;}
inline void access(int x){
for(ri y=0;x;y=x,x=fa[x]){
splay(x);int tmp;
if(tmp=find(ch[x][1]))up(1,1,n,dfn[tmp],dfn[tmp]+siz[tmp]-1,1);
if(tmp=find(ch[x][1]=y))up(1,1,n,dfn[tmp],dfn[tmp]+siz[tmp]-1,-1);
}
}
//操作
inline void op1(int x){access(x);}
inline int op2(int x,int y){int fa=lca(x,y);return 1+qy(1,1,n,dfn[x],dfn[x])+qy(1,1,n,dfn[y],dfn[y])-(qy(1,1,n,dfn[fa],dfn[fa])<<1);}
inline int op3(int x){return qy(1,1,n,dfn[x],dfn[x]+siz[x]-1);}
signed main(){
// freopen("data.in","r",stdin);
n=in;m=in;
for(ri i=1;i<n;++i){int u=in,v=in;g[u].push_back(v);g[v].push_back(u);}
init();BD(1,1,n);
while(m--){
int op=in;
if(op==1)op1(in);
if(op==2)cout<<op2(in,in)<<'\n';
if(op==3)cout<<op3(in)<<'\n';
}
return 0;
}