#轻重链剖分,线段树#洛谷 3703 [SDOI2017]树点涂色

题目传送门


分析

可以发现相同的颜色一定组成一个连通块。

那么操作2就相当于 \(f_x+f_y-2*f_{lca}+1\)

操作3就相当于询问 \(f\) 的最大值。

最关键的就是操作1,考虑往上跳,在同颜色与同重链之间选深度较大的一个。

那么就是要把重链上的这一段染成新的颜色,在线段树上维护颜色以及f值。

现在的链顶的子树所有的 \(f\) 都要减1,并且如果之前子树的点操作过那么就要撤销回来。

然后如果当前点不是原颜色的链底,那么当前点的那一子节点的子树就要整体加一。

颜色的链顶和链底可以在修改的时候动态维护,这样时间复杂度就是两个 \(\log\)


代码

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
using namespace std;
const int N=100011; struct node{int y,next;}e[N<<1]; vector<int>K[N];
int as[N],dep[N],siz[N],tot,ext,n,m,et=1,fat[N],big[N],Top[N],dfn[N],rfn[N],nfd[N];
int lazy[N<<2],w[N<<2],col[N<<2],ct[N<<1],cb[N<<1];
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void print(int ans){
    if (ans>9) print(ans/10);
	putchar(ans%10+48); 
} 
void dfs1(int x,int fa){
	dep[x]=dep[fa]+1,siz[x]=1,fat[x]=fa;
	for (int i=as[x],SIZ=-1;i;i=e[i].next)
	if (e[i].y!=fa){
		dfs1(e[i].y,x),siz[x]+=siz[e[i].y];
	    if (SIZ<siz[e[i].y]) big[x]=e[i].y,SIZ=siz[e[i].y];
	}
}
void dfs2(int x,int linp){
	dfn[x]=++tot,nfd[tot]=x,Top[x]=linp;
	if (!big[x]) return;
	dfs2(big[x],linp),K[x].push_back(dfn[big[x]]);
	for (int i=as[x];i;i=e[i].next)
	if (e[i].y!=fat[x]&&e[i].y!=big[x])
	    dfs2(e[i].y,e[i].y),K[x].push_back(dfn[e[i].y]);
}
int max(int a,int b){return a>b?a:b;}
void build(int k,int l,int r){
	if (l==r){
		w[k]=dep[nfd[l]],col[k]=nfd[l];
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	w[k]=max(w[k<<1],w[k<<1|1]);
}
int lca(int x,int y){
	for (;Top[x]!=Top[y];x=fat[Top[x]])
	    if (dep[Top[x]]<dep[Top[y]]) x^=y,y^=x,x^=y;
    return dep[x]<dep[y]?x:y;
}
void ptag(int k,int z){w[k]+=z,lazy[k]+=z;}
void update(int k,int l,int r,int x,int y,int z){
	if (l==x&&r==y) {ptag(k,z); return;}
    int mid=(l+r)>>1;
    if (lazy[k]){
		ptag(k<<1,lazy[k]);
		ptag(k<<1|1,lazy[k]);
		lazy[k]=0;
	}
	if (y<=mid) update(k<<1,l,mid,x,y,z);
	else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
	    else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
	w[k]=max(w[k<<1],w[k<<1|1]);
}
void upd(int k,int l,int r,int x,int y,int z){
	if (l==x&&r==y) {col[k]=z; return;}
    int mid=(l+r)>>1;
    if (y<=mid) upd(k<<1,l,mid,x,y,z);
    else if (x>mid) upd(k<<1|1,mid+1,r,x,y,z);
    else upd(k<<1,l,mid,x,mid,z),upd(k<<1|1,mid+1,r,mid+1,y,z);
}
int query_col(int k,int l,int r,int x){
	if (l==r) return col[k];
	int mid=(l+r)>>1;
	if (x<=mid) return max(col[k],query_col(k<<1,l,mid,x));
	    else return max(col[k],query_col(k<<1|1,mid+1,r,x));
}
int query(int k,int l,int r,int x,int y){
	if (l==x&&r==y) return w[k];
	int mid=(l+r)>>1;
	if (lazy[k]){
		ptag(k<<1,lazy[k]);
		ptag(k<<1|1,lazy[k]);
		lazy[k]=0;
	}
	if (y<=mid) return query(k<<1,l,mid,x,y);
	else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
	else return max(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
void Update(int x){
	ct[++ext]=1,cb[ext]=x;
	for (int lst=0,Ct=0;x;x=fat[lst]){
		int col=query_col(1,1,n,dfn[x]);
		int w=query(1,1,n,dfn[x],dfn[x]);
		if (x!=cb[col]){
			int now=nfd[*(--upper_bound(K[x].begin(),K[x].end(),dfn[cb[col]]))];
			if (now!=lst) update(1,1,n,dfn[now],rfn[now],1),Ct=now;
		}
		if (dep[ct[col]]<dep[Top[x]]){
			update(1,1,n,dfn[Top[x]],rfn[Top[x]],1-w);
			upd(1,1,n,dfn[Top[x]],dfn[x],ext);
			if (lst) update(1,1,n,dfn[lst],rfn[lst],w-1);
			lst=Top[x];
		}else{
			update(1,1,n,dfn[ct[col]],rfn[ct[col]],1-w);
			upd(1,1,n,dfn[ct[col]],dfn[x],ext);
			if (lst) update(1,1,n,dfn[lst],rfn[lst],w-1);
			lst=ct[col],ct[col]=Ct;
		}
	}
}
int main(){
	ext=n=iut(),m=iut();
	for (int i=1;i<n;++i){
		int x=iut(),y=iut();
		e[++et]=(node){y,as[x]},as[x]=et;
		e[++et]=(node){x,as[y]},as[y]=et;
	}
	for (int i=1;i<=n;++i) ct[i]=cb[i]=i;
	dfs1(1,0),dfs2(1,1),build(1,1,n);
	for (int i=1;i<=n;++i) rfn[i]=dfn[i]+siz[i]-1;
	for (int i=1;i<=m;++i){
		int opt=iut(),x=iut();
		switch (opt){
			case 1:{
				Update(x);
				break;
			}
			case 2:{
				int y=iut(),Lca=lca(x,y),t0,t1,t2;
				t0=query(1,1,n,dfn[x],dfn[x]);
				t1=query(1,1,n,dfn[y],dfn[y]);
				t2=query(1,1,n,dfn[Lca],dfn[Lca]);
				print(t0+t1-t2*2+1),putchar(10);
				break;
			}
			case 3:{
				print(query(1,1,n,dfn[x],rfn[x])),putchar(10);
				break;
			}
		}
	}
	return 0;
}
posted @ 2022-03-22 20:39  lemondinosaur  阅读(19)  评论(0编辑  收藏  举报