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

本文深入解析轻重链剖分(HLD)算法,一种高效的数据结构用于解决树形结构上的路径查询和更新问题。通过链式前向星、线段树等数据结构优化查询效率,适用于大规模数据集的快速处理。

P3384 【模板】轻重链剖分
code:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <iomanip>
//
using namespace std;
const int INF = 0x3f3f3f3f;//1.06e9大小
const int mod1 = 1e9 + 7;
const int mod2 = 998244353;
const int mod3 = 1e9;
const double PI = acos ( -1 );
const double eps = 1e-8;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned uint;
const int sq5 = 616991993;
inline int read()
{
	int X=0; bool flag=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
	if(flag) return X;
	return ~(X-1);
}
#define ms(x,n) memset(x,n,sizeof(x))
#define debug(x) printf("***%d***\n",x)
#define pii pair<int ,int>
#define X first
#define Y second
#define pb push_back
#define mid ((l+r)>>1)
#define ls k<<1
#define rs k<<1|1
#define lowbit a&(-a)
const int maxn = 2e5 + 10;
//
int n , m ,r ,mod;
int e ,beg[maxn],nx[maxn],to[maxn],w[maxn],wt[maxn];
//链式前向星,w[],wt[]初始化点权数组
int a[maxn<<2],lazy[maxn<<2];
//线段树操作
int son[maxn] , id[maxn] , fa[maxn] , cnt , dep[maxn] , sz[maxn ], top[maxn];
//    重儿子       新编号  父亲节点  dfs序     深度     子树大小   树链顶端结点
int res ;//查询答案;
inline void add(int u,int v)
{//链式前向星的加点操作
	to[++e] = v;
	nx[e] = beg[u];
	beg[u] = e;
}
inline void pushdown(int k,int lenn)
{//lazy标志的下传
	lazy[ls] += lazy[k];
	lazy[rs] += lazy[k];
	a[ls] += lazy[k]*(lenn-(lenn>>1));
	a[rs] += lazy[k]*(lenn>>1);
	a[ls]%=mod;
	a[rs]%=mod;
	lazy[k] = 0;
}
inline void build(int k,int l,int r)
{
	if(l==r)
	{
		a[k] = wt[l];
		a[k]%=mod;
		return ;
	}
	build(ls,l,mid);
	build(rs,mid+1,r);
	a[k] = (a[ls]+a[rs])%mod;
}
inline void query(int k,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)
	{
		res+=a[k];
		res%=mod;
		return ;
	}
	else
	{
		if(lazy[k])pushdown(k,r-l+1);
		if(L<=mid)query(ls,l,mid,L,R);
		if(R>mid)query(rs,mid+1,r,L,R);
	}
}
inline void update(int k,int l,int r,int L,int R,int x)
{
	if(L<=l&&r<=R)
	{
		lazy[k]+=x;
		a[k]+=x*(r-l+1);
	}
	else
	{
		if(lazy[k])pushdown(k,r-l+1);
		if(L<=mid)update(ls,l,mid,L,R,x);
		if(R>mid)update(rs,mid+1,r,L,R,x);
		a[k] = (a[ls]+a[rs])%mod;
	}
}
//线段树板子结束了
inline int chain_que(int u,int v)
{
	int ans =0 ;
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]])swap(u,v);//把x点改为所在链顶端深度更深的那个点
		res = 0;
		query(1,1,n,id[top[u]],id[u]);//ans+=x点到x所在链顶端 这一段区间的点权和
		ans += res;
		ans%=mod;
		u = fa[top[u]];//x跳到x所在链顶端那个点上面一点
	}
	//已经同链
	if(dep[u]>dep[v])swap(u,v);//把x点深度更深的那个点
	res =0;
	query(1,1,n,id[u],id[v]);
	ans += res;
	return ans%mod;
}
inline void chain_update(int u,int v,int x)
{
	x%=mod;
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		update(1,1,n,id[top[u]],id[u],x);
		u = fa[top[u]];
	}
	if(dep[u]>dep[v])swap(u,v);
	update(1,1,n,id[u],id[v],x);
}
inline int str_que(int k)
{
	res =0 ;
	query(1,1,n,id[k],id[k]+sz[k]-1);//字数区间右端点id[k]+sz[k]+1
	return res;
}
inline void str_update(int k,int x)
{
	update(1,1,n,id[k],id[k]+sz[k]-1,x);
}
inline void dfs1(int k,int f,int deep)
{
	dep[k] = deep;
	fa[k] = f;
	sz[k] =1;
	int maxson =-1;//重儿子的子树大小
	for(int i=beg[k];i;i=nx[i])
	{
		int y = to[i];
		if(y == f)continue;//如果为父亲就continue
		dfs1(y,k,deep+1);
		sz[k] +=sz[y];//处理出来的儿子加到自己身上
		if(sz[y]>maxson)son[k]= y,maxson=sz[y];
	}
}
inline void dfs2(int k,int topf)//x当前节点,topf当前链最顶端结点
{
	id[k]=++cnt;
	wt[cnt] = w[k];
	top[k] = topf;
	if(!son[k])return ;
	dfs2(son[k],topf);
	for(int i = beg[k];i;i=nx[i])
	{
		int y =to[i];
		if(y==fa[k]||y==son[k])continue;
		dfs2(y,y);
	}
}
int main()
{
	cin>>n>>m>>r>>mod;
	for(int i=1;i<=n;++i)
	{
		w[i] = read();
	}
	for(int i =1;i<n;++i)
	{
		int a,b;
		a=read();b=read();
		add(a,b);add(b,a);
	}
	dfs1(r,0,1);
	dfs2(r,r);
	build(1,1,n);
	while(m--)
	{
		int k,x,y,z;
		k = read();
		if(k==1)
		{
			x=read();y=read();z=read();
			chain_update(x,y,z);
		}
		else if(k==2)
		{
			x = read();y = read();
			printf("%d\n",chain_que(x,y));
		}
		else if(k==3)
		{
			x=read();y=read();
			str_update(x,y);
		}
		else
		{
			x=read();
			printf("%d\n",str_que(x));
		}
	}
	return 0;
}


基于粒子群优化算法的p-Hub选址优化(Matlab代码实现)内容概要:本文介绍了基于粒子群优化算法(PSO)的p-Hub选址优化问题的研究与实现,重点利用Matlab进行算法编程和仿真。p-Hub选址是物流与交通网络中的关键问题,旨在通过确定最优的枢纽节点位置和非枢纽节点的配方式,最小化网络总成本。文章详细阐述了粒子群算法的基本原理及其在解决组合优化问题中的适应性改进,结合p-Hub中转网络的特点构建数学模型,并通过Matlab代码实现算法流程,包括初始化、适应度计算、粒子更新与收敛判断等环节。同时可能涉及对算法参数设置、收敛性能及不同规模案例的仿真结果析,以验证方法的有效性和鲁棒性。; 适合人群:具备一定Matlab编程基础和优化算法理论知识的高校研究生、科研人员及从事物流网络规划、交通系统设计等相关领域的工程技术人员。; 使用场景及目标:①解决物流、航空、通信等网络中的枢纽选址与路径优化问题;②学习并掌握粒子群算法在复杂组合优化问题中的建模与实现方法;③为相关科研项目或实际工程应用提供算法支持与代码参考。; 阅读建议:建议读者结合Matlab代码逐段理解算法实现逻辑,重点关注目标函数建模、粒子编码方式及约束处理策略,并尝试调整参数或拓展模型以加深对算法性能的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值