树链剖分

P3384 【模板】轻重链剖分/树链剖分

题目描述:
如题,已知一棵包含 N 个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
1 x y z,表示将树从 xy 结点最短路径上所有节点的值都加上 z
2 x y ,表示求树从 xy 结点最短路径上所有节点的值之和。
3 x z,表示将以 x 为根节点的子树内所有节点值都加上 z
4 x 表示求以 x 为根节点的子树内所有节点值之和

很好的学习题解!
OI-wiki!

一些概念:

  • 重子节点:表示其子节点中子树最大的子结点。如果有多个子树最大的子结点,取其一。如果没有子节点,就无重子节点
  • 轻子节点:表示剩余的所有子结点。
  • 从这个结点到重子节点的边为 重边。
  • 到其他轻子节点的边为 轻边。
  • 若干条首尾衔接的重边构成 重链。
  • 把落单的结点也当作重链,那么整棵树就被剖分成若干条重链。

基本思路

  • dfs1处理dep[]节点深度,fa[]父亲节点,sz[]子树大小,son[]重儿子
  • dfs2处理id[]节点新编号,rk[]新编号节点对应点权, top[]每条链因此的顶点
  • 对于子节点,先访问重儿子再访问轻儿子,因此重链内的DFN序是连续的,而一颗子树内的DFN序是连续的,故可以使用线段树和树状数组维护权值和
  • 当我们要处理任意两点间路径时,每次选择深度较大的链往上跳,直到两点在同一条链上。

My Code

#include<bits/stdc++.h>
#define il inline
#define ri register
#define cs const
#define pc(i) putchar(i)
using namespace std;
cs int N=2e5+7;
il void read(int &as)
{
	as=0;int f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();as*=f;
}
void wt(int x){if(x<0) x=-x,pc('-');if(x>9) wt(x/10);pc(x%10|48);}
struct node{int to,nxt;}e[N];
int t[N<<2],lz[N<<2];
int n,m,r,Mod,h[N],v[N],eoe;
int dep[N],son[N],id[N],fa[N],sz[N],top[N],rk[N],dfn;
il void add(cs int u,cs int v){e[++eoe]={v,h[u]},h[u]=eoe;}
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define len (r-l+1)
il void pushup(cs int rt){t[rt]=(t[ls]+t[rs])%Mod;}
il void pushdown(cs int rt,cs int l,cs int r)
{
	if(!lz[rt]) return;
	lz[ls]+=lz[rt],(t[ls]+=lz[rt]*(mid-l+1))%=Mod;
	lz[rs]+=lz[rt],(t[rs]+=lz[rt]*(r-mid))%=Mod,lz[rt]=0;
}
void build(cs int rt,cs int l,cs int r)
{
	if(l==r) return (t[rt]=v[rk[l]])%=Mod,void();
	build(ls,l,mid),build(rs,mid+1,r),pushup(rt);
}
void update(cs int rt,cs int l,cs int r,cs int ql,cs int qr,cs int k)
{
	if(ql<=l&&r<=qr) return (t[rt]+=len*k)%=Mod,lz[rt]+=k,void();
	pushdown(rt,l,r);
	if(ql<=mid) update(ls,l,mid,ql,qr,k);
	if(qr>mid) update(rs,mid+1,r,ql,qr,k);
	pushup(rt);
}
int query(cs int rt,cs int l,cs int r,cs int ql,cs int qr)
{
	if(ql<=l&&r<=qr) return t[rt]%Mod;
	int re=0; pushdown(rt,l,r);
	if(ql<=mid) (re+=query(ls,l,mid,ql,qr))%=Mod;
	if(qr>mid) (re+=query(rs,mid+1,r,ql,qr))%=Mod;
	return re;
}
#undef ls
#undef rs
#undef mid
#undef len
void dfs1(cs int u,cs int Fa)//dep,fa,sz,hson
{
	dep[u]=dep[Fa]+1,fa[u]=Fa,sz[u]=1;int hs=-1;
	for(ri int i=h[u];i;i=e[i].nxt)
	{
		if(e[i].to==Fa) continue;
		dfs1(e[i].to,u),sz[u]+=sz[e[i].to];
		if(sz[e[i].to]>hs) son[u]=e[i].to,hs=sz[e[i].to];
	}
}
void dfs2(cs int u,cs int tp)//id,rk,top
{
	id[u]=++dfn,rk[dfn]=u,top[u]=tp;
	if(!son[u]) return;
	dfs2(son[u],tp);
	for(ri int i=h[u];i;i=e[i].nxt)
		if(e[i].to!=fa[u]&&e[i].to!=son[u]) 
			dfs2(e[i].to,e[i].to);
}
il int qRange(int a,int b)
{
	int re=0;
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		(re+=query(1,1,n,id[top[a]],id[a]))%=Mod,a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return (re+=query(1,1,n,id[a],id[b]))%=Mod,re;
}
il void updRange(int a,int b,cs int k)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		update(1,1,n,id[top[a]],id[a],k),a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	update(1,1,n,id[a],id[b],k);
}
il int qSon(cs int u){return query(1,1,n,id[u],id[u]+sz[u]-1);}
il void updSon(cs int u,cs int k){update(1,1,n,id[u],id[u]+sz[u]-1,k);}
signed main()
{
	read(n),read(m),read(r),read(Mod);
	for(ri int i=1;i<=n;++i) read(v[i]);
	for(ri int i=1,u,v;i<n;++i) 
		read(u),read(v),add(u,v),add(v,u);
	dfs1(r,0),dfs2(r,r),build(1,1,n);
	for(ri int i=1,op,x,y,z;i<=m;++i)
	{
		read(op);
		if(op==1) read(x),read(y),read(z),updRange(x,y,z);
		else if(op==2) read(x),read(y),wt(qRange(x,y)),pc('\n');
		else if(op==3) read(x),read(z),updSon(x,z);
		else read(x),wt(qSon(x)),pc('\n');
	}
	return 0;
} 

树剖求LCA

感觉比板子简单捏(

点击查看代码
#include<bits/stdc++.h>
#define cs const
#define il inline
#define ri register
#define pc(i) putchar(i)
using namespace std;
il void read(int &as)
{
	as=0;int f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();as*=f;
}
void wt(int x){if(x<0) x=-x,pc('-');if(x>9) wt(x/10);pc(x%10|48);}
cs int N=5e5+7; 
struct node{int nxt,to;}e[N<<1];
int n,m,r,sz[N],top[N],id[N],rk[N],dep[N],son[N],fa[N],h[N],eoe,dfn;
il void add(cs int u,cs int v){e[++eoe]={h[u],v},h[u]=eoe;}
void dfs1(cs int u,cs int Fa)
{
	dep[u]=dep[Fa]+1,sz[u]=1,fa[u]=Fa;int hs=-1;
	for(ri int i=h[u];i;i=e[i].nxt)
	{
		if(e[i].to==Fa) continue;
		dfs1(e[i].to,u),sz[u]+=sz[e[i].to];
		if(hs<sz[e[i].to]) son[u]=e[i].to,hs=sz[e[i].to];
	}
}
void dfs2(cs int u,cs int tp)
{
	top[u]=tp,id[u]=++dfn,rk[dfn]=u;
	if(!son[u]) return;
	dfs2(son[u],tp); 
	for(ri int i=h[u];i;i=e[i].nxt)
		if(e[i].to!=son[u]&&e[i].to!=fa[u]) 
			dfs2(e[i].to,e[i].to);
}
il int lca(int a,int b)
{
	while(top[a]!=top[b]) 
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	return dep[a]<dep[b]?a:b;
}
signed main()
{
	read(n),read(m),read(r);
	for(ri int i=1,u,v;i<n;++i) 
		read(u),read(v),add(u,v),add(v,u);
	dfs1(r,0),dfs2(r,r);
	for(ri int i=1,a,b;i<=m;++i)
		read(a),read(b),wt(lca(a,b)),pc('\n');
	return 0;
}
 

P2590 [ZJOI2008]树的统计

单点修改,加了一个路径最大值,改下线段树就行,记得传进线段树的编号要套上一个id[]……

点击查看代码
#include<bits/stdc++.h>
#define cs const
#define il inline
#define ri register
#define pc(i) putchar(i)
using namespace std;
cs int N=5e5+7,inf=1e9+7; 
struct node{int nxt,to;}e[N<<1];
int t[N<<2][2],h[N],eoe,v[N];
int n,q,sz[N],top[N],id[N],rk[N],dep[N],son[N],fa[N],dfn;
il void add(cs int u,cs int v){e[++eoe]={h[u],v},h[u]=eoe;}
#define mid (l+r>>1)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define len (r-l+1)
il void pushup(cs int rt)
{
	t[rt][0]=t[ls][0]+t[rs][0],
	t[rt][1]=max(t[ls][1],t[rs][1]);
}
void build(cs int rt,cs int l,cs int r)
{
	if(l==r) return t[rt][0]=t[rt][1]=v[rk[l]],void(); 
	build(ls,l,mid),build(rs,mid+1,r),pushup(rt);
}
void update(cs int rt,cs int l,cs int r,cs int q,cs int k)
{
	if(l==r) return t[rt][0]=t[rt][1]=k,void();
	if(q<=mid) update(ls,l,mid,q,k);
	else update(rs,mid+1,r,q,k);
	pushup(rt);
}
int querySum(cs int rt,cs int l,cs int r,cs int ql,cs int qr)
{
	if(ql<=l&&r<=qr) return t[rt][0];
	int re=0;  
	if(ql<=mid) re+=querySum(ls,l,mid,ql,qr);
	if(qr>mid) re+=querySum(rs,mid+1,r,ql,qr);
	return re;
}
int queryMax(cs int rt,cs int l,cs int r,cs int ql,cs int qr)
{
	if(ql<=l&&r<=qr) return t[rt][1];
	int re=-inf; 
	if(ql<=mid) re=max(re,queryMax(ls,l,mid,ql,qr));
	if(qr>mid) re=max(re,queryMax(rs,mid+1,r,ql,qr));
	return re;
}
#undef mid 
#undef  ls
#undef rs
#undef len
void dfs1(cs int u,cs int Fa)
{
	dep[u]=dep[Fa]+1,sz[u]=1,fa[u]=Fa;int hs=-1;
	for(ri int i=h[u];i;i=e[i].nxt)
	{
		if(e[i].to==Fa) continue;
		dfs1(e[i].to,u),sz[u]+=sz[e[i].to];
		if(hs<sz[e[i].to]) son[u]=e[i].to,hs=sz[e[i].to];
	}
}
void dfs2(cs int u,cs int tp)
{
	top[u]=tp,id[u]=++dfn,rk[dfn]=u;
	if(!son[u]) return;
	dfs2(son[u],tp); 
	for(ri int i=h[u];i;i=e[i].nxt)
		if(e[i].to!=son[u]&&e[i].to!=fa[u]) 
			dfs2(e[i].to,e[i].to);
}
il int qRange(int a,int b)
{
	int re=0;
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		re+=querySum(1,1,n,id[top[a]],id[a]),a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return re+=querySum(1,1,n,id[a],id[b]),re;
}
il int qMax(int a,int b)
{
	int re=-inf;
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		re=max(re,queryMax(1,1,n,id[top[a]],id[a])),a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b); 
	return max(re,queryMax(1,1,n,id[a],id[b]));
}
signed main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(ri int i=1,u,v;i<n;++i) 
		cin>>u>>v,add(u,v),add(v,u);
	for(ri int i=1;i<=n;++i) cin>>v[i];
	dfs1(1,0),dfs2(1,1),build(1,1,n);
	cin>>q;
	for(ri int i=1,u,v,t;i<=q;++i)
	{
		char op[10]; cin>>op;
		if(op[0]=='C') cin>>u>>t,update(1,1,n,id[u],t);//id[u]
		else if(op[1]=='M') cin>>u>>v,cout<<qMax(u,v)<<'\n';
		else cin>>u>>v,cout<<qRange(u,v)<<'\n';
	}
	return 0;
}

[HAOI2015]树上操作

甚至比模板简单(开long long

点击查看代码
#include<bits/stdc++.h>
#define il inline
#define ri register
#define cs const
#define pc(i) putchar(i)
#define int long long
using namespace std;
cs int N=2e5+7;
il void read(int &as)
{
	as=0;int f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();as*=f;
}
void wt(int x){if(x<0) x=-x,pc('-');if(x>9) wt(x/10);pc(x%10|48);}
struct node{int to,nxt;}e[N];
int t[N<<2],lz[N<<2];
int n,m,r,h[N],v[N],eoe;
int dep[N],son[N],id[N],fa[N],sz[N],top[N],rk[N],dfn;
il void add(cs int u,cs int v){e[++eoe]={v,h[u]},h[u]=eoe;}
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define len (r-l+1)
il void pushup(cs int rt){t[rt]=t[ls]+t[rs];}
il void pushdown(cs int rt,cs int l,cs int r)
{
	if(!lz[rt]) return;
	lz[ls]+=lz[rt],t[ls]+=lz[rt]*(mid-l+1);
	lz[rs]+=lz[rt],t[rs]+=lz[rt]*(r-mid),lz[rt]=0;
}
void build(cs int rt,cs int l,cs int r)
{
	if(l==r) return t[rt]=v[rk[l]],void();
	build(ls,l,mid),build(rs,mid+1,r),pushup(rt);
}
void update(cs int rt,cs int l,cs int r,cs int ql,cs int qr,cs int k)
{
	if(ql<=l&&r<=qr) return t[rt]+=len*k,lz[rt]+=k,void();
	pushdown(rt,l,r);
	if(ql<=mid) update(ls,l,mid,ql,qr,k);
	if(qr>mid) update(rs,mid+1,r,ql,qr,k);
	pushup(rt);
}
int query(cs int rt,cs int l,cs int r,cs int ql,cs int qr)
{
	if(ql<=l&&r<=qr) return t[rt];
	int re=0; pushdown(rt,l,r);
	if(ql<=mid) re+=query(ls,l,mid,ql,qr);
	if(qr>mid) re+=query(rs,mid+1,r,ql,qr);
	return re;
}
#undef ls
#undef rs
#undef mid
#undef len
void dfs1(cs int u,cs int Fa)//dep,fa,sz,hson
{
	dep[u]=dep[Fa]+1,fa[u]=Fa,sz[u]=1;int hs=-1;
	for(ri int i=h[u];i;i=e[i].nxt)
	{
		if(e[i].to==Fa) continue;
		dfs1(e[i].to,u),sz[u]+=sz[e[i].to];
		if(sz[e[i].to]>hs) son[u]=e[i].to,hs=sz[e[i].to];
	}
}
void dfs2(cs int u,cs int tp)//id,rk,top
{
	id[u]=++dfn,rk[dfn]=u,top[u]=tp;
	if(!son[u]) return;
	dfs2(son[u],tp);
	for(ri int i=h[u];i;i=e[i].nxt)
		if(e[i].to!=fa[u]&&e[i].to!=son[u]) 
			dfs2(e[i].to,e[i].to);
}
il int qRange(int a,int b)
{
	int re=0;
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		re+=query(1,1,n,id[top[a]],id[a]),a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return re+=query(1,1,n,id[a],id[b]),re;
}
il void updRange(int a,int b,cs int k)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		update(1,1,n,id[top[a]],id[a],k),a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	update(1,1,n,id[a],id[b],k);
}
il void updSon(cs int u,cs int k){update(1,1,n,id[u],id[u]+sz[u]-1,k);}
signed main()
{
//	freopen("1.in","r",stdin);
	read(n),read(m);
	for(ri int i=1;i<=n;++i) read(v[i]);
	for(ri int i=1,u,v;i<n;++i) 
		read(u),read(v),add(u,v),add(v,u);
	dfs1(1,0),dfs2(1,1),build(1,1,n);
	for(ri int i=1,op,x,y,z;i<=m;++i)
	{
		read(op);
		if(op==1) read(x),read(z),updRange(x,x,z);
		else if(op==2) read(x),read(z),updSon(x,z);
		else read(x),wt(qRange(1,x)),pc('\n');
	}
	return 0;
} 

P3833 [SHOI2012]魔法树

甚至比模板简单

点击查看代码
#include<bits/stdc++.h>
#define il inline
#define ri register
#define cs const
#define pc(i) putchar(i)
#define int long long
using namespace std;
cs int N=2e5+7;
il void read(int &as)
{
	as=0;int f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();as*=f;
}
il void Ro(char &ch){ch=' ';while(ch!='A'&&ch!='Q')ch=getchar();}
void wt(int x){if(x<0) x=-x,pc('-');if(x>9) wt(x/10);pc(x%10|48);}
struct node{int to,nxt;}e[N];
int t[N<<2],lz[N<<2];
int n,m,r,h[N],v[N],eoe;
int dep[N],son[N],id[N],fa[N],sz[N],top[N],rk[N],dfn;
il void add(cs int u,cs int v){e[++eoe]={v,h[u]},h[u]=eoe;}
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define len (r-l+1)
il void pushup(cs int rt){t[rt]=t[ls]+t[rs];}
il void pushdown(cs int rt,cs int l,cs int r)
{
	if(!lz[rt]) return;
	lz[ls]+=lz[rt],t[ls]+=lz[rt]*(mid-l+1);
	lz[rs]+=lz[rt],t[rs]+=lz[rt]*(r-mid),lz[rt]=0;
}
void build(cs int rt,cs int l,cs int r)
{
	if(l==r) return t[rt]=v[rk[l]],void();
	build(ls,l,mid),build(rs,mid+1,r),pushup(rt);
}
void update(cs int rt,cs int l,cs int r,cs int ql,cs int qr,cs int k)
{
	if(ql<=l&&r<=qr) return t[rt]+=len*k,lz[rt]+=k,void();
	pushdown(rt,l,r);
	if(ql<=mid) update(ls,l,mid,ql,qr,k);
	if(qr>mid) update(rs,mid+1,r,ql,qr,k);
	pushup(rt);
}
int query(cs int rt,cs int l,cs int r,cs int ql,cs int qr)
{
	if(ql<=l&&r<=qr) return t[rt];
	int re=0; pushdown(rt,l,r);
	if(ql<=mid) re+=query(ls,l,mid,ql,qr);
	if(qr>mid) re+=query(rs,mid+1,r,ql,qr);
	return re;
}
#undef ls
#undef rs
#undef mid
#undef len
void dfs1(cs int u,cs int Fa)//dep,fa,sz,hson
{
	dep[u]=dep[Fa]+1,fa[u]=Fa,sz[u]=1;int hs=-1;
	for(ri int i=h[u];i;i=e[i].nxt)
	{
		if(e[i].to==Fa) continue;
		dfs1(e[i].to,u),sz[u]+=sz[e[i].to];
		if(sz[e[i].to]>hs) son[u]=e[i].to,hs=sz[e[i].to];
	}
}
void dfs2(cs int u,cs int tp)//id,rk,top
{
	id[u]=++dfn,rk[dfn]=u,top[u]=tp;
	if(!son[u]) return;
	dfs2(son[u],tp);
	for(ri int i=h[u];i;i=e[i].nxt)
		if(e[i].to!=fa[u]&&e[i].to!=son[u]) 
			dfs2(e[i].to,e[i].to);
}
il void updRange(int a,int b,cs int k)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		update(1,1,n,id[top[a]],id[a],k),a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	update(1,1,n,id[a],id[b],k);
}
il int qSon(cs int u){return query(1,1,n,id[u],id[u]+sz[u]-1);}
signed main()
{
//	freopen("1.in","r",stdin);
	read(n);
	for(ri int i=1,u,v;i<n;++i) 
		read(u),read(v),add(u,v),add(v,u);
	dfs1(0,0),dfs2(0,0),build(1,1,n);
	read(m);
	for(ri int i=1,x,y,z;i<=m;++i)
	{
		char op; Ro(op);
		if(op=='A') read(x),read(y),read(z),updRange(x,y,z);
		else read(x),wt(qSon(x)),pc('\n');
	}
	return 0;
} 


P1505 [国家集训队]旅游

线段树维护区间max,min,sum,修改操作取相反数,这个pushdown坑了我次捏

调了一天很崩溃捏
#include<bits/stdc++.h>
#define il inline
#define ri register
#define cs const
#define pc(i) putchar(i)
using namespace std;
il void read(int &as)
{
	as=0;int f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();as*=f;
}
void wt(int x){if(x<0) x=-x,pc('-');if(x>9) wt(x/10);pc(x%10|48);}
cs int N=2e5+7,inf=INT_MAX;
struct Seg{int lz,sum,Max,Min;}t[N<<2];
struct node{int nxt,to,w;}e[N<<1];
int n,h[N],eoe,r[N][2],m;
int val[N],son[N],top[N],id[N],fa[N],rk[N],dep[N],sz[N],dfn;
il void add(cs int u,cs int v,cs int w){e[++eoe]={h[u],v,w},h[u]=eoe;}
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define len (r-l+1)
il void pushup(cs int rt)
{
	t[rt].Max=max(t[ls].Max,t[rs].Max),
	t[rt].Min=min(t[ls].Min,t[rs].Min),
	t[rt].sum=t[ls].sum+t[rs].sum;
}
il void pushdown(cs int rt)
{
	if(!t[rt].lz) return;
	t[ls].lz^=1,t[rs].lz^=1,t[rt].lz=0;//调了一天能不能趋势 
	int maxx=t[ls].Max,minn=t[ls].Min;
	t[ls]={t[ls].lz,-t[ls].sum,-minn,-maxx};
    maxx=t[rs].Max,minn=t[rs].Min;
	t[rs]={t[rs].lz,-t[rs].sum,-minn,-maxx};
}
void build(cs int rt,cs int l,cs int r)
{
	if(l==r) return t[rt]={0,val[rk[l]],val[rk[l]],val[rk[l]]},void();
	build(ls,l,mid),build(rs,mid+1,r),pushup(rt);
}
void change(cs int rt,cs int l,cs int r,cs int q,cs int k)
{
	if(l==r) return t[rt]={0,k,k,k},void();
	pushdown(rt);
	if(q<=mid) change(ls,l,mid,q,k);
	if(q>mid) change(rs,mid+1,r,q,k);
	pushup(rt);
}
void update(cs int rt,cs int l,cs int r,cs int ql,cs int qr)
{
	if(ql<=l&&r<=qr)
	{
		int maxx=t[rt].Max,minn=t[rt].Min;
		t[rt]={t[rt].lz^1,-t[rt].sum,-minn,-maxx};return;
	}
	pushdown(rt);
	if(ql<=mid) update(ls,l,mid,ql,qr);
	if(qr>mid) update(rs,mid+1,r,ql,qr);
	pushup(rt);
}
int query_min(cs int rt,cs int l,cs int r,cs int ql,cs int qr)
{
	if(ql<=l&&r<=qr) return t[rt].Min;
	int re=inf;pushdown(rt);
	if(ql<=mid) re=min(re,query_min(ls,l,mid,ql,qr));
	if(qr>mid) re=min(re,query_min(rs,mid+1,r,ql,qr));
	return pushup(rt),re;
}
int query_max(cs int rt,cs int l,cs int r,cs int ql,cs int qr)
{
	if(ql<=l&&r<=qr) return t[rt].Max;
	int re=-inf; pushdown(rt);
	if(ql<=mid) re=max(re,query_max(ls,l,mid,ql,qr));
	if(qr>mid) re=max(re,query_max(rs,mid+1,r,ql,qr));
	return pushup(rt),re;
}
int query_sum(cs int rt,cs int l,cs int r,cs int ql,cs int qr)
{
	if(ql<=l&&r<=qr) return t[rt].sum;
	int re=0;pushdown(rt);
	if(ql<=mid) re+=query_sum(ls,l,mid,ql,qr);
	if(qr>mid) re+=query_sum(rs,mid+1,r,ql,qr);
	return pushup(rt),re;
}
#undef ls
#undef rs
#undef mid
#undef len
void dfs1(cs int u,cs int Fa)
{
	dep[u]=dep[Fa]+1,sz[u]=1,fa[u]=Fa;int maxx=-1;
	for(ri int i=h[u];i;i=e[i].nxt)
	{
		if(e[i].to==Fa) continue;
		dfs1(e[i].to,u),sz[u]+=sz[e[i].to],val[e[i].to]=e[i].w;
		if(sz[e[i].to]>maxx) maxx=sz[e[i].to],son[u]=e[i].to;
	}
}
void dfs2(cs int u,cs int tp)
{
	top[u]=tp,id[u]=++dfn,rk[dfn]=u;
	if(!son[u]) return; dfs2(son[u],tp);
	for(ri int i=h[u];i;i=e[i].nxt)
		if(e[i].to!=fa[u]&&e[i].to!=son[u])
			dfs2(e[i].to,e[i].to);
}
il void Chg()
{
	int x,k,a,b; read(x),read(k);
	a=r[x][0]+1,b=r[x][1]+1;
	if(dep[a]<dep[b]) swap(a,b);
	change(1,1,n,id[a],k);
}
il void Upd()
{
	int a,b; read(a),read(b),a++,b++;
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		update(1,1,n,id[top[a]],id[a]),a=fa[top[a]];
	}
	if(a==b) return;
	if(dep[a]>dep[b]) swap(a,b);
	update(1,1,n,id[a]+1,id[b]);
}
il void QSum()
{
	int a,b,re=0;read(a),read(b),a++,b++;
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		re+=query_sum(1,1,n,id[top[a]],id[a]),a=fa[top[a]];
	}
	if(a==b) return wt(re),pc('\n'),void();
	if(dep[a]>dep[b]) swap(a,b);
	re+=query_sum(1,1,n,id[a]+1,id[b]),wt(re),pc('\n');
}
il void QMax()
{
	int a,b,re=-inf; read(a),read(b),a++,b++;
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		re=max(re,query_max(1,1,n,id[top[a]],id[a])),a=fa[top[a]];
	}
	if(a==b) return wt(re),pc('\n'),void();
	if(dep[a]>dep[b]) swap(a,b);
	re=max(re,query_max(1,1,n,id[a]+1,id[b])),wt(re),pc('\n');	
}
il void QMin()
{
	int a,b,re=inf; read(a),read(b),a++,b++;
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		re=min(re,query_min(1,1,n,id[top[a]],id[a])),a=fa[top[a]];
	}
	if(a==b) return wt(re),pc('\n'),void();
	if(dep[a]>dep[b]) swap(a,b);
	re=min(re,query_min(1,1,n,id[a]+1,id[b])),wt(re),pc('\n');	
}
signed main()
{
	read(n);
	for(ri int i=1,w;i<n;++i)
		read(r[i][0]),read(r[i][1]),read(w),
		add(r[i][0]+1,r[i][1]+1,w),add(r[i][1]+1,r[i][0]+1,w);
	read(m),dfs1(1,0),dfs2(1,1),build(1,1,n);
	for(ri int i=1;i<=m;++i)
	{
		char op[5]; scanf("%s",op);
		if(op[0]=='C') Chg();
		else if(op[0]=='N') Upd();
		else if(op[0]=='S') QSum();
		else if(op[1]=='A')	QMax();
		else QMin();
	}
	return 0;
}

upd1.31:及后续内容
参考资料:https://oiwiki.org/graph/hld/
https://www.luogu.com.cn/blog/zengqinyi/solution-p3384

posted @   Bertidurlah  阅读(23)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示