未来城市规划

2023-10-26

未来城市规划

题目描述

n n n 个节点的树, m m m 次操作。每个边都有初始边权 c [ i ] c[i] c[i],定义 f ( u , v ) f(u, v) f(u,v) 为节点 u u u 到节点 v v v 的简单路径上边权之和。
共有两种操作。

  • 操作 1 1 1(INC):把 u u u 号节点到 v v v 号节点的简单路径上所有边权 c [ i ] c[i] c[i] 增加 w w w

  • 操作 2 2 2(ASK):设 S S S 为以点 p p p 为根节点的子树内所有节点(包括 p p p 点)的集合,求 ∑ i ∈ S , j ∈ S , i < j f ( i , j ) \sum _{i \in S, j \in S, i < j} f(i, j) iS,jS,i<jf(i,j)

数据范围

1 ≤ n , m ≤ 5 × 1 0 4 , 1 ≤ c i ≤ 1000 , 0 ≤ w ≤ 1000 , 1 ≤ p ≤ n 1 ≤ n, m ≤ 5 \times 10^{4},1 ≤ c_i≤ 1000,0 \le w \le 1000, 1 \le p \le n 1n,m5×104,1ci10000w1000,1pn


题解报告

树链剖分。方便起见,边权均转化为深度较大点的点权(根节点无点权,其点权也不会参与计算中)。

操作 1 1 1 是树链剖分 + + + 线段树的基本操作,

对于操作 2 2 2 ,考虑询问的节点 p p p,观察后发现,每个节点 i i i 对答案的贡献为 v a l [ i ] ∗ s i z [ i ] ∗ ( s i z [ p ] − s i z [ i ] ) val[i] * siz[i] * (siz[p] - siz[i]) val[i]siz[i](siz[p]siz[i])

v a l [ i ] ∗ s i z [ i ] ∗ s i z [ p ] − v a l [ i ] ∗ s i z [ i ] ∗ s i z [ i ] val[i] * siz[i] * siz[p] - val[i] * siz[i] * siz[i] val[i]siz[i]siz[p]val[i]siz[i]siz[i],( p p p s i z [ p ] siz[p] siz[p] 是已知的)

所以只要每个节点维护 v a l [ i ] ∗ s i z [ i ] val[i] * siz[i] val[i]siz[i] v a l [ i ] ∗ s i z [ i ] ∗ s i z [ i ] val[i] * siz[i] * siz[i] val[i]siz[i]siz[i] 的信息即可。

所以操作 2 2 2 其实就是区间求和操作。

AC代码:

#include <bits/stdc++.h>
#define ll long long
#define int ll
#define nls node[cnt].ls
#define nrs node[cnt].rs
using namespace std;
const int maxn = 2e5 + 5;
const int mod = 2019;

struct Node {
	int sum1, sum2;
	int siz1, siz2;
	int ls, rs;
	int lazy;
}node[maxn << 2];
int n, m, tot;
int fa[maxn], son[maxn], siz[maxn], dep[maxn];
int dfn[maxn], rk[maxn], top[maxn], bot[maxn];
int val[maxn], sum1[maxn], sum2[maxn];
vector <int> adj[maxn];

void init () {}

void dfs1 (int f, int u, int d) {
	fa[u] = f, siz[u] = 1, dep[u] = d;
	for (auto it : adj[u]) {
		if (it == f) continue;
		dfs1 (u, it, d + 1);
		siz[u] += siz[it];
		if (siz[it] > siz[son[u]]) son[u] = it;
	}
	siz[u] = siz[u] % mod;
	sum1[u] = val[u] * siz[u] % mod;
	sum2[u] = (val[u] * siz[u]) % mod * siz[u] % mod;
}

void dfs2 (int f, int u, int tp) {
	dfn[u] = ++tot, rk[tot] = u, top[u] = tp;
	if (son[u]) dfs2 (u, son[u], tp);
	for (auto it : adj[u]) {
		if (it == f || it == son[u]) continue;
		dfs2 (u, it, it);
	}
	bot[u] = tot;
}

void update (int cnt) {
	node[cnt].sum1 = (node[nls].sum1 + node[nrs].sum1) % mod;
	node[cnt].sum2 = (node[nls].sum2 + node[nrs].sum2) % mod;
	node[cnt].siz1 = (node[nls].siz1 + node[nrs].siz1) % mod;
	node[cnt].siz2 = (node[nls].siz2 + node[nrs].siz2) % mod;
}

void build (int cnt, int l, int r) {
	if (l == r) {
		node[cnt].sum1 = sum1[rk[l]] % mod;
		node[cnt].sum2 = sum2[rk[l]] % mod;
		node[cnt].siz1 = siz[rk[l]] % mod;
		node[cnt].siz2 = siz[rk[l]] * siz[rk[l]] % mod;
		node[cnt].lazy = 0;
		return;
	}
	int mid = l + r >> 1;
	build (nls = ++tot, l, mid);
	build (nrs = ++tot, mid + 1, r);
	update (cnt);
}

void pushdown (int cnt) {
	node[nls].sum1 = (node[nls].sum1 + node[cnt].lazy * node[nls].siz1) % mod;
	node[nrs].sum1 = (node[nrs].sum1 + node[cnt].lazy * node[nrs].siz1) % mod;
	
	node[nls].sum2 = (node[nls].sum2 + node[cnt].lazy * node[nls].siz2) % mod;
	node[nrs].sum2 = (node[nrs].sum2 + node[cnt].lazy * node[nrs].siz2) % mod;
	
	node[nls].lazy = (node[nls].lazy + node[cnt].lazy) % mod;
	node[nrs].lazy = (node[nrs].lazy + node[cnt].lazy) % mod;
	
	node[cnt].lazy = 0;
}

void modify (int cnt, int l, int r, int ql, int qr, int k) {
	if (l >= ql && r <= qr) {
		node[cnt].sum1 = (node[cnt].sum1 + node[cnt].siz1 * k) % mod;
		node[cnt].sum2 = (node[cnt].sum2 + node[cnt].siz2 * k) % mod;
		node[cnt].lazy = (node[cnt].lazy + k) % mod;
		return;
	}
	int mid = l + r >> 1;
	pushdown (cnt);
	if (ql <= mid) modify (nls, l, mid, ql, qr, k);
	if (qr > mid) modify (nrs, mid + 1, r, ql, qr, k);
	node[cnt].sum1 = (node[nls].sum1 + node[nrs].sum1) % mod;
	node[cnt].sum2 = (node[nls].sum2 + node[nrs].sum2) % mod;
}

void add_path (int u, int v, int w) {
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap (u, v);
		modify (0, 1, n, dfn[top[u]], dfn[u], w);
		u = fa[top[u]];
	}
	if (dep[u] > dep[v]) swap (u, v);
	if (u == v) return;
	modify (0, 1, n, dfn[u] + 1, dfn[v], w);
}

int query (int cnt, int l, int r, int ql, int qr, int x) {
	if (l >= ql && r <= qr) return (node[cnt].sum1 * x - node[cnt].sum2) % mod;
	int mid = l + r >> 1, res = 0;
	pushdown (cnt);
	if (ql <= mid) res += query (nls, l, mid, ql, qr, x);
	if (qr > mid) res += query (nrs, mid + 1, r, ql, qr, x);
	return ((res % mod) + mod) % mod;
}

void charming () {
	cin >> n >> m;
	for (int i = 2, q, c; i <= n; ++i) {
		cin >> q >> c;
		adj[q].emplace_back (i);
		val[i] = c;
	}
	dfs1 (0, 1, 1), dfs2 (0, 1, 1);
	tot = 0, build (0, 1, n);
	char opt[5];
	int u, v, w, p;
	for (int i = 1; i <= m; ++i) {
		cin >> opt + 1;
		if (opt[1] == 'I') {
			cin >> u >> v >> w;
			add_path (u, v, w % mod);
		}
		else {
			cin >> p;
			if (dfn[p] == bot[p]) cout << 0 << endl;//这里很奇怪我改成 siz[p] == 1 就不对了
			else cout << query (0, 1, n, dfn[p] + 1, bot[p], siz[p]) << endl;
		}
	}
}

signed main () {
	charming ();
	return 0;
}

收获&总结

难度不是很大,但是也需要一定的思考,把要计算的数据做个小的转变方便储存。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

未来城市规划 的相关文章

  • 如何将点光源转换为卵形/椭圆形?

    我希望通过具有不同 x 和 y 值的 vec2 半径将当前的圆形光变成椭圆形 有没有办法根据我当前在片段着色器中的代码来做到这一点 uniform struct Light vec4 colour vec3 position vec2 ra
  • lambda 始终返回“1”

    有这样的代码 include
  • Microsoft Visual C++ 2008 和 R2007b 的 Mex 类型

    我想对 vs2008 和 matlab2007b 使用 mex 类型 我尝试了下面的代码 include
  • 这个洗牌算法有什么问题吗?

    我一直在做一些休闲假期计算 我的迷你项目是模拟意大利游戏 tomboli 一个关键的组成部分是对以下过程的模拟 游戏由一名男子控制 他拿着一袋 90 个弹珠 编号为 1 到 90 他从袋中随机取出一颗弹珠 每次向玩家喊出弹珠编号 经过一番思
  • 从 proc/pid/cmdline 解析命令行参数

    我正在尝试解析命令行参数另一个程序 这是一个模拟器 在我的程序中使用system 命令和模拟器的pid 不幸的是同时使用文件读取和cat 输出格式不正确 所以我无法真正获取数据 cat在命令行上显示删除了空格的文件内容 整个字符串粘在一起
  • 相当于一个允许重复键的排序字典

    我需要一个数据结构 可以通过与对象关联的浮动键对对象进行排序 从低到低的在前 问题是键代表成本 所以经常有重复 我不关心这一点 因为如果两个具有相同的成本 我只会抓住第一个 因为它没有区别 问题是编译器抱怨 是否有一种数据结构的行为方式相同
  • 如何获取字符串宽度

    我需要在类库中构建一个函数 该函数接受一个字符串和该字符串的特定字体 然后获取字符串的宽度 那么我怎样才能得到字符串边界宽度呢 另一种方法是使用TextRenderer 并致电its MeasureString http msdn micr
  • 一个阻塞但非模态的 QDialog?

    我有一堆图像 我想对其执行一些操作 处理完每个图像后 我的程序应该弹出一个对话框 提示用户是否要继续处理下一个图像或中止 在此之前 他们应该有机会对图像或参数进行一些手动更改 无论如何 他们必须能够访问应用程序的窗口 而调用对话框的方法的执
  • 如何为用户提供给定 boost::spirit 语法的自动完成建议?

    我正在使用 Boost Spirit 在我的 C GUI 应用程序中为非技术用户构建简单的 数据过滤器 语言 语言与纯英语非常相似 并且可以解析为 AST 我被要求使该过程尽可能对用户友好 因此我希望提供类似 CLang 的错误消息 无法识
  • 策略模式的现实示例

    我一直在读关于OCP原理 http en wikipedia org wiki Open closed principle以及如何使用策略模式来实现这一目标 我打算尝试向几个人解释这一点 但我能想到的唯一例子是根据 订单 的状态使用不同的验
  • .NET 配置(app.config/web.config/settings.settings)

    我有一个 NET 应用程序 它具有用于调试和发布版本的不同配置文件 例如 调试 app config 文件指向开发SQL服务器 http en wikipedia org wiki Microsoft SQL Server它启用了调试并且发
  • 在 C、C++ 中实现腐蚀、膨胀

    我对二值图像的膨胀是如何完成的有理论上的了解 AFAIK 如果我的 SE 结构元素 是这样的 0 1 1 1 在哪里 代表中心 我的图像 二进制是这样的 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0
  • invoke_result获取模板成员函数的返回类型

    如何获取模板成员函数的结果类型 下面的最小示例说明了该问题 include
  • 从 WMI 运行 exe 时的网络身份验证

    我有一个 C exe 需要使用 WMI 运行并访问网络共享 但是 当我访问共享时 我收到 UnauthorizedAccessException 如果我直接运行 exe 则可以访问共享 我在这两种情况下都使用相同的用户帐户 我的应用程序有两
  • C/C++ 特殊 CPU 功能的使用

    我很好奇 新的编译器是否使用了新 CPU 中内置的一些额外功能 例如 MMX SSE 3DNow 所以 我的意思是 在最初的 8086 中甚至没有 FPU 所以旧的编译器甚至不能使用它 但新的编译器可以 因为 FPU 是每个新 CPU 的一
  • 在 Qt C++ 中使用多个键

    我正在构建 坦克 游戏 我使用关键事件在地图上运行我的坦克 实际上我当时只能使用一把钥匙 但我需要有能力去完成任务 同时向上和离开 这是我的单键事件代码 switch event gt key case Qt Key Up if ui gt
  • SoapHttpClientProtocol:以流而不是字符串的形式获取响应?

    我正在使用一种网络服务 它可以一次性输出大量数据 响应字符串可能约为 8MB 虽然在台式电脑上这不是问题 但嵌入式设备在处理 8MB 字符串对象时会发疯 我想知道是否有办法以流的形式获取响应 目前我正在使用如下方法 我尝试使用 POST 请
  • 使用 std::set 时重载运算符<

    这是我第一次使用 std set 容器 并且我对操作符 std less 遇到了问题 我声明该集合 std set
  • 通过 boost::python 将 C++ 对象传递给 python 函数

    我想在 C 应用程序中使用嵌入 python 并调用 python 脚本中定义的函数 该函数的参数是一个 C 对象 看我的代码 class Test public void f std cout lt lt sss lt
  • C# 泛型中的通配符等效项

    假设我有一个通用类 如下所示 public class GeneralPropertyMap

随机推荐

  • Node中的事件循环

    Node中的事件循环 Node的底层语言是libuv 使用v8引擎解析js脚本 libuv负责调用接口API 将不同的任务交给不同的线程处理 再将处理结果交给v8引擎 v8引擎再将处理结果发送给用户 Node中任务的执行顺序 timers定
  • Mybatis-Plus:Service接口

    目录 IService接口 1 写实体类 2 写mapper接口 3 写service接口 4 写service接口的实现类 IService自带方法 1 save 2 SaveOrUpdate 3 Remove 4 Update 5 Ge
  • xss-domcobble绕过XSSfilter

    目录 DOM破坏的原理 例题 多层标签 HTMLCollection 一些常见的标签的关系 三层标签如何获取 例题 DOM破坏的原理 DOMClobber是一种攻击技术 它利用了DOM 文档对象模型 的特性来破坏或修改网页的结构和功能 DO
  • WDK李宏毅学习笔记第十五周01_Conditional Generation by Conditional

    Conditional Generation by GAN 文章目录 Conditional Generation by GAN 摘要 1 Supervised Conditional GAN 1 1 目的 1 2 做法 1 3 Discr
  • 把一个base64编码的图片绘制到canvas (canvas的图片在转成dataurl)

    把一个base64编码的图片绘制到canvas 需要引入jquery
  • SpringBoot中ThreadPoolTaskExecutor的使用

    文章目录 1 配置自己的线程池 2 使用 2 1 在Service层使用 2 2 多线程中使用事务的写法 2 3 方法内多线程 2 3 1 错误写法 2 3 2 正确写法 一 2 3 2 正确写法 二 2 3 3 正确写法 三 3 线程池与
  • mysql的相关技术说明_MySQL 系统架构 说明

    说明 本文转自 简朝阳 MySQL ACE 的 MySQL性能调优与架构设计 一 逻辑模块组成 总的来说 MySQL 可以看成是二层架构 第一层我们通常叫做SQL Layer 在MySQL 数据库系统处理底层数据之前的所有工作都是在这一层完
  • 计算机熔断与服务降级,Hystrix---服务熔断和服务降级

    一 服务熔断 防止服务雪崩 作用在服务提供者 服务熔断 熔断机制是应对雪崩效应的一种微服务链路保护机制 当扇出链路的某个微服务不可用或者响应时间太长时 会进行服务的降级 进而熔断该节点微服务的调用 快速返回 错误 的响应信息 当检测到该节点
  • Java多线程——Lock

    Lock 从JDK 5 0开始 Java提供了更强大的线程同步机制 通过显式定义同步锁对象来实现同步 同步锁使用Lock对象充当 java util concurrent locks Lock接口是控制多个线程对共享资源进行访问的工具 锁提
  • Java的静态绑定与动态绑定

    我们可以对思考一个问题 JVM是如何知道调用的是哪个类的方法源代码 这里面到底有什么内幕呢 这篇文章我们就将揭露JVM方法调用的静态 static binding 和动态绑定机制 auto binding 理解这两个绑定之前 我们不妨先理解
  • Vue + Springboot 前后端分离项目实践:项目简介及教程

    专栏目录 持续更新 Vue js Spring Boot 前后端分离项目实践 一 项目简介Vue js Spring Boot 前后端分离项目实践 二 搭建 Vue js 项目Vue js Spring Boot 前后端分离项目实践 三 前
  • Visual Studio 2015 + cmake编译QT5程序

    概述 由于QT的集成开发环境QTCreate 在代码调试功能上远不及Visual Studio方便 因此 在Windows平台 可以使用Visual Studio来开发调试QT程序 本文章就主要介绍下 如何使用CMAKE编译QT5程序 并使
  • 【Unity】SafeArea适配大小

    通过使用SafeArea 修改stretch适配类型的UI画布的Top偏移 适应安卓异型屏幕
  • rust nom 实现一个简单的sql解析器

    rust nom 实现一个简单的sql解析器 祝福 前言 分析 字段 表 查询语句 编码 关键字 字符规则 alias 字段 常规格式的字段处理 字符串格式字段处理 子查询处理 字段处理汇总 表 整个查询语句 结尾 祝福 过年期间 新型冠状
  • socket error总结

    Socket error 0 Directly send error Socket error 10004 Interrupted function call Socket error 10013 Permission denied Soc
  • nfs 成功挂载后,写入时出现permission denied的解决

    nfs服务器端 etc exports文件中已指定 rw 可读可写 在客户端也能正常挂载 可在向挂载目录里写入内容提示 permission denied 后来才搞清楚 nfs在服务器端导出的目录 也有一定权限要求 当把服务端导出目录 修改
  • T88合并两个有序数组

    题目 合并两个有序数组 给你两个有序整数数组 nums1 和 nums2 请你将 nums2 合并到 nums1 中 使 nums1 成为一个有序数组 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 你可以假设 nums1
  • DropDownList控件的数据绑定

    DropDownList控件如何进行数据绑定 简单方法 在单击控件的向右箭头 在 编辑项 里面进行编辑添加 如下图所示 在前台代码中添加 方法一 在页面初始化时候将集合绑定到DropDownList 人工绑定 public void Pag
  • 致 Python 初学者

    文章目录 1 前言 2 明确学习目标 不急于求成 不好高骛远 3 在开始学习 Python 之前 你需要做一些准备 2 1 Python 的各种发行版 2 2 安装 Python 2 3 选择一款趁手的开发工具 3 习惯使用IDLE 这是学
  • 未来城市规划

    未来城市规划 题目描述 n n n 个节点的树 m m m 次操作 每个边都有初始边权 c