ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-06-02 18:51:20  阅读:235  来源: 互联网

标签:LCT 树点 text Access int 涂色 res 操作


「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]));
		}
	}
}



标签:LCT,树点,text,Access,int,涂色,res,操作
来源: https://www.cnblogs.com/chasedeath/p/13033040.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有