1. 程式人生 > 實用技巧 >luogu P4315 月下“毛景樹” 題解

luogu P4315 月下“毛景樹” 題解

題目連結

前言

這大概是本蒟蒻A掉的題裡面碼量最大的一道題了。我自認為碼風比較緊湊,但還是寫了180行。

從下午2點多調到晚上8點。中間小錯不斷。最後還是藉助了郭神的AC程式碼。。

%%%stO郭神Orz%%%

還是我程式碼能力不夠。以後要多寫一些這樣的題練練手。

解析:

題目相當裸。樹鏈剖分+線段樹維護區間最大值。
需要注意的點大致如下:
1.邊權化點權
2.線段樹需要實現的功能:區間加,區間賦值,區間查詢最大值。
看起來貌似有手就行其實對於郭神這樣的神犇確實有手就行,但是本蒟蒻調了一下午。。。

犯的其實都是一些低錯,大概如下:
1.3個modify函式用串了
2.樹鏈剖分跳top的時候,注意是 \(dfn[top[u]]<=dfn[u]\)

,因此應該是modifyfz(1,1,n,dfn[top[u]],dfn[u],w);
而不是modifyfz(1,1,n,dfn[u],dfn[top[u]],w);
3.注意在pushdown的時候要先判一下有沒有區間賦值標記。

真正因為有理解上的問題而犯的錯誤:
在區間修改時要下傳標記。每次更新前要保證該節點的狀態一定是最新的,否則就會出錯。

完整程式碼:

#include <bits/stdc++.h>
using namespace std;
const int maxn=100000+10;
int n,cnt,Time;
int head[maxn],tree[maxn<<2],lazyfz[maxn<<2],lazyadd[maxn<<2],top[maxn],fa[maxn],son[maxn],size[maxn],depth[maxn],dfn[maxn],w[maxn];
struct node{
	int to,next,val;
}edge[maxn<<1];
struct Node{
	int from,to;
}b[maxn];
void add(int from,int to,int val){
	edge[++cnt].to=to;
	edge[cnt].val=val;
	edge[cnt].next=head[from];
	head[from]=cnt;
}
void dfs1(int u,int f){
	fa[u]=f;
	size[u]=1;
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(v==f) continue;
		depth[v]=depth[u]+1;
		dfs1(v,u);
		size[u]+=size[v];
		if(size[v]>size[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int t,int s){
	top[u]=t;
	dfn[u]=++Time;
	w[Time]=s;
	if(son[u]){
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].to;
			if(v==son[u]){
				dfs2(v,t,edge[i].val);
				break;
			}
		}
	}
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(v==fa[u]||v==son[u]) continue;
		dfs2(v,v,edge[i].val);
	}
}
void build(int rt,int l,int r){
	lazyfz[rt]=-1;
	if(l==r){
		tree[rt]=w[l];
		return;
	}
	int mid=(l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void updatefz(int rt,int w){
	tree[rt]=lazyfz[rt]=w;
	lazyadd[rt]=0;
}
void updateadd(int rt,int w){
	tree[rt]+=w;
	lazyadd[rt]+=w;
}
void pushdown(int rt){
	if(lazyfz[rt]!=-1){
		updatefz(rt<<1,lazyfz[rt]);
		updatefz(rt<<1|1,lazyfz[rt]);
		lazyfz[rt]=-1;
	}
	if(lazyadd[rt]){
		updateadd(rt<<1,lazyadd[rt]);
		updateadd(rt<<1|1,lazyadd[rt]);
		lazyadd[rt]=0;
	}
}
void modifyadd(int rt,int l,int r,int s,int t,int w){
	if(s<=l&&r<=t){
		updateadd(rt,w);
		return;
	}
	int mid=(l+r)>>1;
	pushdown(rt);
	if(s<=mid) modifyadd(rt<<1,l,mid,s,t,w);
	if(t>mid) modifyadd(rt<<1|1,mid+1,r,s,t,w);
	tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void Modify(int u,int v,int w){
	while(top[u]!=top[v]){
		if(depth[top[u]]<depth[top[v]]) swap(u,v);
		modifyadd(1,1,n,dfn[top[u]],dfn[u],w);
		u=fa[top[u]];
	}
	if(v==u) return;
	if(depth[u]>depth[v]) swap(u,v);
	modifyadd(1,1,n,dfn[u]+1,dfn[v],w);
}
void modifyfz(int rt,int l,int r,int s,int t,int w){
	if(s<=l&&r<=t){
		updatefz(rt,w);
		return;
	}
	int mid=(l+r)>>1;
	pushdown(rt);
	if(s<=mid) modifyfz(rt<<1,l,mid,s,t,w);
	if(t>mid) modifyfz(rt<<1|1,mid+1,r,s,t,w);
	tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void Cover(int u,int v,int w){
	while(top[u]!=top[v]){
		if(depth[top[u]]<depth[top[v]]) swap(u,v);
		modifyfz(1,1,n,dfn[top[u]],dfn[u],w);
		u=fa[top[u]];
	}
	if(v==u) return;
	if(depth[u]>depth[v]) swap(u,v);
	modifyfz(1,1,n,dfn[u]+1,dfn[v],w);
}
int query(int rt,int l,int r,int s,int t){
	if(s<=l&&r<=t) return tree[rt];
	int mid=(l+r)>>1;
	pushdown(rt);
	if(t<=mid) return query(rt<<1,l,mid,s,t);
	if(s>mid) return query(rt<<1|1,mid+1,r,s,t);
	else return max(query(rt<<1,l,mid,s,t),query(rt<<1|1,mid+1,r,s,t));
}
int Query(int u,int v){
	int res=-100000000;
	while(top[u]!=top[v]){
		if(depth[top[u]]<depth[top[v]]) swap(u,v);
		res=max(res,query(1,1,n,dfn[top[u]],dfn[u]));
		u=fa[top[u]];
	}
	if(u==v) return res;
	if(depth[u]>depth[v]) swap(u,v);
	res=max(res,query(1,1,n,dfn[u]+1,dfn[v]));
	return res;
}
void Solve(){
	scanf("%d",&n);
	for(int i=1,x,y,z;i<n;++i){
		scanf("%d%d%d",&x,&y,&z);
		b[i].from=x;
		b[i].to=y;
		add(x,y,z);
		add(y,x,z);
	}
	dfs1(1,0);
	dfs2(1,1,0);
	build(1,1,n);
	char ccc[10];
	int x,y,z;
	while(1){
		scanf("%s",ccc);
		if(ccc[0]=='S') return;
		if(ccc[0]=='C'){
			if(ccc[1]=='h'){
				scanf("%d%d",&x,&y);
				int d=max(dfn[b[x].from],dfn[b[x].to]);
				modifyfz(1,1,n,d,d,y);
			}else{
				scanf("%d%d%d",&x,&y,&z);
				Cover(x,y,z);
			}
		}else if(ccc[0]=='A'){
			scanf("%d%d%d",&x,&y,&z);
			Modify(x,y,z);
		}else{
			scanf("%d%d",&x,&y);
			printf("%d\n",Query(x,y));
		}
	}
}
int main(){
	Solve();
	return 0;
}