Luogu P3384(树链剖分,裸题)

一个代码模板。

题目描述

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

输入输出格式

输入格式:

 

第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

 

输出格式:

 

输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模

 

输入输出样例

输入样例#1: 复制

5 5 2 24
7 3 7 8 0 
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3

输出样例#1: 复制

2
21
#include <bits/stdc++.h>
#define mem(x,v) memset(x,v,sizeof(x)) 
#define go(i,a,b)  for (int i = a; i <= b; i++)
#define og(i,a,b)  for (int i = a; i >= b; i--)
#define MID(a,b) (a + b) / 2
#define lson now << 1
#define rson now << 1 | 1
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 1e5+100;
int n,m,r,p; //正常读入。
int lazy[N<<2],val[N<<2]; //线段树。
int cnt = -1,Head[N],Next[N],to[N],w[N],wt[N];//权值,邻接表
int son[N],id[N],f[N],tim,size[N],top[N],dep[N];//树剖数组。
// 重儿子,入队时间戳,父亲节点,子树大小,链的顶端,深度。
int res = 0;
void Add_edge(int u, int v){
	to[++cnt] = v;
	Next[cnt] = Head[u];
	Head[u] = cnt;
}
void dfs1(int u, int fa, int deep){ //解决深度,子树大小,重儿子,父亲节点。
	dep[u] = deep; //deep
	f[u] = fa; size[u] = 1;// father , size of node.
	for (int i = Head[u]; i != -1; i = Next[i]){
		int v = to[i];
		if (v == fa) continue;
		dfs1(v,u,deep+1);
		size[u] += size[v]; //size of u.
		if (size[v] > size[son[u]]) son[u] = v; // 找u 的重儿子。
	}
}
void dfs2(int u, int topf){
	id[u] = ++tim; //时间戳
	wt[tim] = w[u];//权值
	top[u] = topf; //找链顶。
	if (!son[u]) return;
	dfs2(son[u],topf); //先找重儿子,
	for (int i = Head[u]; i != -1; i = Next[i]){ //再找轻儿子。
		int v = to[i];
		if (v == f[u] || v == son[u]) continue; //如果是重儿子,或者父亲节点,跳过。
		dfs2(v,v);
	}
}
// 线段树操作
void push_down(int now, int len){
	if (lazy[now] == 0) return;
	val[lson] = (val[lson] + lazy[now]*(len >> 1)) % p;
	val[rson] = (val[rson] + lazy[now]*(len - (len >> 1))) % p;
	lazy[lson] = (lazy[lson] + lazy[now]);
	lazy[rson] = (lazy[rson] + lazy[now]);
	lazy[now] = 0;
}
void Build(int now, int a, int b){
	if (a + 1 == b){
		val[now] = wt[a] % p;
		return;
	}
	int m = MID(a,b);
	Build(lson,a,m); Build(rson,m,b);
	val[now] = (val[lson] + val[rson]) % p;
}
int Query(int now, int a, int b, int l, int r){
	int ans = 0;
	if (l <= a && r >= b - 1){
		return (val[now] % p);
	}
	int m = MID(a,b);
	push_down(now,b-a);
	if (l < m) ans = (ans + Query(lson,a,m,l,r))%p;
	if (r >= m) ans = (ans + Query(rson,m,b,l,r)) % p;
	return ans;
}

void Insert(int now, int a, int b, int l, int r, int k){
	if (l <= a && r >= b - 1){
		val[now] = (val[now] + k * (b - a))%p;
		lazy[now] += k;
		return;
	}
	push_down(now,b-a);
	int m = MID(a,b);
	if (l < m) Insert(lson,a,m,l,r,k);
	if (r >= m) Insert(rson,m,b,l,r,k);
	val[now] = (val[lson] + val[rson]) % p;
}
// 线段树操作
int qRange(int x, int y){
	int ans = 0;
	while(top[x] != top[y]){
		if (dep[top[x]] < dep[top[y]]) swap(x,y); // 把 x 变成深度大的点。
		ans = (ans + Query(1,1,n+1,id[top[x]],id[x])) % p;//处理路径上的和。
		x = f[top[x]]; //到达链顶的父亲节点,就是换一条链。
	}
	if (dep[x] < dep[y]) swap(x,y);//在同一条链,不一定相等。把x 变成深度大的点。
	ans = (ans + Query(1,1,1+n,id[y],id[x])) % p; //处理路径上的和。
	return ans;
}
void upRange(int x, int y, int k){ //同上。
	k %= p;
	while(top[x] != top[y]){
		if (dep[top[x]] < dep[top[y]]) swap(x,y);
		Insert(1,1,n+1,id[top[x]],id[x],k);
		x = f[top[x]];
	}
	if (dep[x] < dep[y]) swap(x,y);
	Insert(1,1,n+1,id[y],id[x],k);
}
int qSon(int x){
	return Query(1,1,n+1,id[x],id[x]+size[x]-1);
}

void upSon(int x, int k){
	Insert(1,1,n+1,id[x],id[x] + size[x] -1,k);
}

int main(){
	scanf("%d%d%d%d",&n,&m,&r,&p);
	go(i,1,n) scanf("%d",&w[i]);
	mem(Head,-1);
	go(i,2,n){
		int x,y;
		scanf("%d%d",&x,&y);
		Add_edge(x,y); Add_edge(y,x);
	}
	dfs1(r,0,1);
	dfs2(r,r);
	Build(1,1,n+1);
	while(m--){
		int op,x,y,z;
		scanf("%d",&op);
		if (op == 1){
			scanf("%d%d%d",&x,&y,&z);
			upRange(x,y,z);
		} else 
		if (op == 2) {
			scanf("%d%d",&x,&y);
			printf("%d\n",qRange(x,y));
		} else
		if (op == 3){
			scanf("%d%d",&x,&y);
			upSon(x,y);
		} else {
			scanf("%d",&x);
			printf("%d\n",qSon(x));
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值