「SDOI2017」树点涂色(LCT+线段树)

「SDOI2017」树点涂色(LCT+线段树)

可以发现更新操作就是\(\text{LCT}\)\(\text{Access}\)操作,这个操作复杂度是\(O(n\log n)\)

因此,考虑对于每次的\(\text{Access}\)操作,维护每个点到根的路径上不同的权值个数

每次\(\text{Access}\)操作只设计到合并两个链/断开一条链两种操作,可以通过线段树维护子树修改

那么修改的复杂度就是\(O(n\log^2 n)\)

对于二操作,自己模拟一下就知道,就是两个点的答案-2\(\cdot \text{LCA}\)答案+1

实现上有一些细节,就是更新的子树根节点是需要查询得到的

const int N=1e5+10;

int n,m;
vector <int> G[N];
int L[N],R[N],dfn;
int son[N][2],fa[N],tfa[N][18],dep[N],id[N];
int s[N<<2],t[N<<2],mi[N];

void Upd(int p,int l,int r,int ql,int qr,int x) {
	if(ql<=l && r<=qr) {
		t[p]+=x;
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) Upd(p<<1,l,mid,ql,qr,x);
	if(qr>mid) Upd(p<<1|1,mid+1,r,ql,qr,x);
	s[p]=max(t[p<<1]+s[p<<1],t[p<<1|1]+s[p<<1|1]);
}
int Que(int p,int l,int r,int ql,int qr) {
	if(ql<=l && r<=qr) return s[p]+t[p];
	int mid=(l+r)>>1,res=-1e9;
	if(ql<=mid) cmax(res,Que(p<<1,l,mid,ql,qr));
	if(qr>mid) cmax(res,Que(p<<1|1,mid+1,r,ql,qr));
	return res+t[p];
}
int Que(int p,int l,int r,int x) {
	int res=0;
	while(1) {
		if(l==r) return res+s[p]+t[p];
		int mid=(l+r)>>1;
		res+=t[p];
		if(x<=mid) p<<=1,r=mid;
		else p=p<<1|1,l=mid+1;
	}
}
void Build(int p,int l,int r) {
	if(l==r) { s[p]=dep[id[l]]+1; return; }
	int mid=(l+r)>>1;
	Build(p<<1,l,mid),Build(p<<1|1,mid+1,r);
	s[p]=max(s[p<<1],s[p<<1|1]);
}

int dir(int x){ return son[fa[x]][1]==x; }
int isroot(int x){ return !fa[x] || (son[fa[x]][0]!=x && son[fa[x]][1]!=x); } 
void Up(int p) { mi[p]=son[p][0]?mi[son[p][0]]:p; }
void rotate(int u) {
	int f=fa[u],ff=fa[f],d=dir(u);
	fa[u]=ff; if(!isroot(f)) son[ff][dir(f)]=u;
	son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
	son[u][!d]=f,fa[f]=u; Up(f),Up(u);
}
void Splay(int x){ for(;!isroot(x);rotate(x)) if(!isroot(fa[x])) rotate((dir(x)^dir(fa[x]))?x:fa[x]); }
void Access(int x) {
	for(int t=0,y;x;t=x,x=fa[x]) {
		Splay(x),y=son[x][1];
		if(y) Upd(1,1,n,L[mi[y]],R[mi[y]],1);
		if(t) Upd(1,1,n,L[mi[t]],R[mi[t]],-1);
		son[x][1]=t,Up(x);
	}
} // LCT模板

void dfs(int u,int f) {
	mi[u]=u,fa[u]=tfa[u][0]=f,id[L[u]=++dfn]=u;
	for(int i=1;(1<<i)<=dep[u];++i) tfa[u][i]=tfa[tfa[u][i-1]][i-1];
	for(int v:G[u]) if(v!=f) dep[v]=dep[u]+1,dfs(v,u);
	R[u]=dfn;
}
int LCA(int x,int y) {
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=0,del=dep[x]-dep[y];(1<<i)<=del;++i) if(del&(1<<i)) x=tfa[x][i];
	if(x==y) return x;
	drep(i,17,0) if(tfa[x][i]!=tfa[y][i]) x=tfa[x][i],y=tfa[y][i];
	return tfa[x][0];
}

int main(){
	n=rd(),m=rd();
	rep(i,2,n) {
		int u=rd(),v=rd();
		G[u].pb(v),G[v].pb(u);
	}
	dfs(1,0),Build(1,1,n);
	rep(i,1,m) {
		int opt=rd();
		if(opt==1) Access(rd());
		else if(opt==2) {
			int x=rd(),y=rd(),z=LCA(x,y);
			printf("%d\n",Que(1,1,n,L[x])+Que(1,1,n,L[y])-2*Que(1,1,n,L[z])+1);
		} else {
			int x=rd();
			printf("%d\n",Que(1,1,n,L[x],R[x]));
		}
	}
}



posted @ 2020-06-02 18:47  chasedeath  阅读(206)  评论(0编辑  收藏  举报