【月下“毛景树”】树链剖分

版权声明:小蒟蒻的博客转载也请注明出处哦 https://blog.csdn.net/qq_42835823/article/details/86625169

月下“毛景树”

在这里插入图片描述
在这里插入图片描述

应该一看都知道是树链剖分吧,但这道题细节特别多。

树链剖分入门

  • 把边权转到深度较深的点上,这样可以用树链剖分操作了
  • 操作路径的时候,两个点的 L C A LCA 不能被改动和统计
  • 懒标记需要两个,且覆盖标记的优先级要高于加的标记,每次传递,修改覆盖标记,要把加标记清为零
  • 覆盖标记初始化为 1 -1 ,因为可能会覆盖为零
  • 最好不要复制粘贴,有些地方未修改到,就很难查错
  • 单个树枝的修改要找到那条树枝中深度较深的点再修改

最重要的: 板子别打错!!!
向上跳 T O P TOP L C A LCA 时应是 i f ( d e p [ t o p [ u ] ] < d e p [ t o p [ v ] ] ) s w a p ( u , v ) ; if(dep[top[u]]<dep[top[v]])swap(u,v);
而非 i f ( d e p [ u ] < d e p [ v ] ) s w a p ( u , v ) ; if(dep[u]<dep[v])swap(u,v);

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct edge{
	int v,w,nxt;
}e[N<<1];
int first[N],cnt=0;
inline void add(int u,int v,int w){
	e[++cnt].v=v;e[cnt].w=w;
	e[cnt].nxt=first[u];first[u]=cnt;
}
int fa[N],dep[N],siz[N],son[N],pos[N],idx[N],top[N],tot,val[N];
void dfs1(int x,int f){
	fa[x]=f;
	dep[x]=dep[f]+1;
	siz[x]=1;
	for(int i=first[x];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==f)continue;
		dfs1(v,x);
		siz[x]+=siz[v];
		if(siz[v]>siz[son[x]])son[x]=v;
		val[v]=e[i].w;
	}
}
void dfs2(int x){
	if(son[x]){
		pos[son[x]]=++tot;
		idx[tot]=son[x];
		top[son[x]]=top[x];
		dfs2(son[x]);
	}
	for(int i=first[x];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==son[x]||v==fa[x])continue;
		pos[v]=++tot;
		idx[tot]=v;
		top[v]=v;
		dfs2(v);
	}
}
#define lc (p<<1)
#define rc (p<<1|1)
struct tree{
	int l,r,mx,laz1,laz2;//改和加 
}t[N<<2];
int n;
void build(int p,int l,int r){
	t[p].l=l;t[p].r=r;t[p].laz1=-1;t[p].laz2=0;
	if(l==r){
		t[p].mx=val[idx[l]];
		return;
	}
	int mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	t[p].mx=max(t[lc].mx,t[rc].mx);
}
void init(){
	dfs1(1,0);
	idx[1]=top[1]=pos[1]=tot=1;
	dfs2(1);
	build(1,1,n);
}
void pushdown(int p){//////////////////////////////////
	if(~t[p].laz1){
		t[lc].mx=t[p].laz1;
		t[lc].laz1=t[p].laz1;
		t[lc].laz2=0;
		t[rc].mx=t[p].laz1;
		t[rc].laz1=t[p].laz1;
		t[rc].laz2=0;
		t[p].laz1=-1;
	}
	if(t[p].laz2>0){
		t[lc].mx+=t[p].laz2;
		t[lc].laz2+=t[p].laz2;
		t[rc].mx+=t[p].laz2;
		t[rc].laz2+=t[p].laz2;
		t[p].laz2=0;
	}
}
void ADD(int p,int l,int r,int v){
	if(l<=t[p].l&&t[p].r<=r){
		t[p].mx+=v;
		t[p].laz2+=v;
		return;
	}
	pushdown(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(l<=mid)ADD(lc,l,r,v);
	if(mid<r)ADD(rc,l,r,v);
	t[p].mx=max(t[lc].mx,t[rc].mx);
}
void change(int p,int l,int r,int v){
	if(l<=t[p].l&&t[p].r<=r){
		t[p].mx=v;
		t[p].laz1=v;//
		t[p].laz2=0;//如果直接覆盖,就不用再加了 
		return;
	}
	pushdown(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(l<=mid)change(lc,l,r,v);
	if(mid<r)change(rc,l,r,v);
	t[p].mx=max(t[lc].mx,t[rc].mx);
}
int query(int p,int l,int r){
	if(l<=t[p].l&&t[p].r<=r)return t[p].mx;
	pushdown(p);
	int mid=(t[p].l+t[p].r)>>1,ans=-2e9;
	if(l<=mid)ans=max(ans,query(lc,l,r));
	if(mid<r)ans=max(ans,query(rc,l,r));
	return ans;
}
void pathadd(int u,int v,int w){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		ADD(1,pos[top[u]],pos[u],w);
		u=fa[top[u]];
	}
	if(dep[u]<dep[v])swap(u,v);
	ADD(1,pos[v]+1,pos[u],w);//不算LCA 
}
void pathchange(int u,int v,int w){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		change(1,pos[top[u]],pos[u],w);
		u=fa[top[u]];
	}
	if(dep[u]<dep[v])swap(u,v);
	change(1,pos[v]+1,pos[u],w);//不算LCA 
}
int pathquery(int u,int v){
	int ans=-2e9;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);//---加上top---------------------------------------------------------------------------//
		ans=max(ans,query(1,pos[top[u]],pos[u]));
		u=fa[top[u]];
	}
	if(dep[u]<dep[v])swap(u,v);
	ans=max(ans,query(1,pos[v]+1,pos[u]));//不算LCA 
	return ans;
}
int u[N],v[N],w[N];
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d%d",&u[i],&v[i],&w[i]);
		add(u[i],v[i],w[i]);add(v[i],u[i],w[i]);
	}
	init();
	char s[10];
	int x,y,z;
	while(1){
		scanf("%s",s+1);
		if(s[1]=='S')break;
		if(s[1]=='C'&&s[2]=='h'){
			scanf("%d%d",&x,&y);
			if(dep[u[x]]>dep[v[x]])change(1,pos[u[x]],pos[u[x]],y);
			else change(1,pos[v[x]],pos[v[x]],y);//修改树枝 
		}
		if(s[1]=='C'&&s[2]=='o'){
			scanf("%d%d%d",&x,&y,&z);
			pathchange(x,y,z);
		}
		if(s[1]=='A'){
			scanf("%d%d%d",&x,&y,&z);
			pathadd(x,y,z);
		}
		if(s[1]=='M'){
			scanf("%d%d",&x,&y);
			printf("%d\n",pathquery(x,y));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42835823/article/details/86625169
今日推荐