题解:CF593D Happy Tree Party

Description

Bogdan has a birthday today and mom gave him a tree consisting of \(n\) vertecies. For every edge of the tree \(i\) , some number \(x_i\) was written on it. In case you forget, a tree is a connected non-directed graph without cycles. After the present was granted, \(m\) guests consecutively come to Bogdan's party. When the \(i\)-th guest comes, he performs exactly one of the two possible operations:

  1. Chooses some number \(y_i\) , and two vertecies \(a_i\) and \(b_i\). After that, he moves along the edges of the tree from vertex \(a_i\) to vertex \(b_i\) using the shortest path (of course, such a path is unique in the tree). Every time he moves along some edge \(j\) , he replaces his current number \(y_i\) by \(\large y_i =\lfloor \frac{y_i}{x_j} \rfloor\), that is, by the result of integer division \(y_i \ div \ x_j\).
  2. Chooses some edge \(p_i\) and replaces the value written in it \(x_{p_i}\) by some positive integer \(c_i < x_{p_i}\) .

As Bogdan cares about his guests, he decided to ease the process. Write a program that performs all the operations requested by guests and outputs the resulting value \(y_i\) for each \(i\) of the first type.

数据保证 \(2 \leq n,m \leq 2e5, \ 1 \leq x_i \leq 1e18\)

题意:

给出一棵有边权的树。树上共有 \(n\) 个结点,现在给出 \(m\) 个操作,操作有两类:

  1. 给你一个数 \(y\) ,走一条 \(u \to \dots \to v\) 的简单路径,每经过一条权为 \(x\) 的边就令

    \[\large y := \lfloor \frac{y}{x} \rfloor
    \]

    询问最终 \(y\) 的值。

  2. 更改某条边的权。

Algorithm

又到了我最喜欢的板子题环节!

而且本题在洛谷的难度评级是NOI/NOI+/CTSC ,快来水黑题吧!

首先注意到有

\[\Large
\lfloor \frac {\lfloor \frac {\lfloor \frac {\lfloor \frac{y}{x_1} \rfloor}{x_2} \rfloor} {\vdots} \rfloor} {x_n} \rfloor = \lfloor \frac{y} {\prod _ {i = 1} ^ n x_i} \rfloor
\]

于是问题转化为询问树上简单路径边权积。

这是个并不困难的问题,可以简单地用树链剖分 + 线段树解决。

具体地,我们首先提出一个点作为根,这样每条边的两端结点就有了父子关系。然后将边权下放到子节点上,将根节点的权赋为1。

这样就将点权转化为了边权。不过要注意统计边权积的时候,不应该记录端点的权(此处指每条链的顶部结点)。

然后跑一下树链剖分,建立线段树即可,只需要写单点修改和区间查询,懒惰标记都不用挂。

然而,观察数据范围,\(x_i\) 在 \(1e18\) 的量级,走一条简单路径的乘积最大值可能达到

\({10^{18}}^{200000}\),你就是写高精度也存不下这玩意,何况要高精度除呢。

等等,除法?

给定 \(y\) 的值也在 \(1e18\) 的量级,这意味着 \(\prod_{i=1}^n x_i\) 一旦超过了 \(1e18\) ,结果就必然为0了。

当然了,两个 \(1e18\) 乘起来依然会爆 long long ,我们可以

  1. 正统地,取对数解决。或有精度误差,但影响不大。
  2. 还有我__int128_t 和 long double 解决不了的事吗? //啊这,CF 用__int128_t 会CE的

于是,开始写代码吧:

#include<bits/stdc++.h>
using namespace std; typedef long long ll;
int n, m; template<typename T>
inline void read(T &x)
{
char c = getchar(); x = 0;
while(c < '0' || '9' < c) c = getchar();
while('0' <= c && c <= '9')
{
x = (x << 1) + (x << 3) + c - 48;
c = getchar();
}
} struct Mint {
long double val;
Mint():val(1) {}
Mint(ll x):val(x) {}
friend Mint operator * (Mint a, Mint b)
{
long double ret = a.val * b.val;
return (ret > 1e18)? 0: ret;
}
};
Mint &operator *= (Mint &a, Mint b) {
return a = a * b;
} template<const int N, const int M>
class Tree {
private:
int beg[N], nex[M], tar[M], len;
int dep[N], siz[N], fat[N], hea[N];
int top[N], dfn[N], id[N], cnt;
Mint cst[M], vap[N], seg[N << 2]; public:
Tree():len(1), cnt(0) {}
inline void add_edge(int a, int b, ll c)
{
++len;
nex[len] = beg[a], beg[a] = len;
tar[len] = b, cst[len] = c;
} void dfs1(int cur, int pa)
{
dep[cur] = dep[pa] + 1;
fat[cur] = pa, siz[cur] = 1; for(int i = beg[cur]; i; i = nex[i])
{
if(tar[i] == pa) continue;
dfs1(tar[i], cur);
vap[tar[i]] = cst[i];
siz[cur] += siz[tar[i]];
if(hea[cur] == -1 || siz[tar[i]] > siz[hea[cur]])
hea[cur] = tar[i];
}
} void dfs2(int cur, int pa)
{
top[cur] = pa, ++cnt;
dfn[cur] = cnt, id[cnt] = cur; if(hea[cur] == -1) return;
dfs2(hea[cur], pa); for(int i = beg[cur]; i; i = nex[i])
if(tar[i] != hea[cur] && tar[i] != fat[cur])
dfs2(tar[i], tar[i]);
} #define lson (nod <<1)
#define rson ((nod <<1) | 1)
void build(int nod, int lef, int rig)
{
if(lef == rig) seg[nod] = vap[id[lef]];
else
{
int mid = (lef + rig) >> 1;
build(lson, lef, mid);
build(rson, mid + 1, rig);
seg[nod] = seg[lson] * seg[rson];
}
} inline void init_treecut() {
memset(hea, -1, sizeof(hea));
dfs1(1, 0);
dfs2(1, 1);
vap[id[1]] = 1;
build(1, 1, n);
} void update(int nod, int lef, int rig, int goa, Mint val)
{
if(lef == rig) seg[nod] = val;
else
{
int mid = (lef + rig) >> 1;
if(goa <= mid) update(lson, lef, mid, goa, val);
else update(rson, mid + 1, rig, goa, val);
seg[nod] = seg[lson] * seg[rson];
}
} Mint query(int nod, int lef, int rig, int goal, int goar)
{
if(goar < lef || rig < goal) return Mint(1);
if(goal <= lef && rig <= goar) return seg[nod];
Mint ret = 1;
int mid = (lef + rig) >> 1;
ret *= query(lson, lef, mid, goal, goar);
ret *= query(rson, mid + 1, rig, goal, goar);
return ret;
} Mint query_path(int u, int v)
{
Mint ret = 1;
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]]) swap(u, v);
ret *= query(1, 1, n, dfn[top[u]], dfn[u]);
u = fat[top[u]];
}
if(dfn[u] > dfn[v]) swap(u, v);
ret *= query(1, 1, n, dfn[u] + 1, dfn[v]);
return ret;
} void update_point(int x, Mint y)
{
int u = tar[x << 1], v = tar[x << 1 | 1];
if(dep[u] < dep[v]) swap(u, v);
update(1, 1, n, dfn[u], y);
} }; Tree<262144, 524288> T;
int main()
{
read(n), read(m); ll x, res;
for(int i = 1, u, v; i != n; ++i)
{
read(u), read(v), read(x);
T.add_edge(u, v, x);
T.add_edge(v, u, x);
} T.init_treecut();
for(int i = 0, a, b, key; i != m; ++i)
{
read(key);
if(key == 1)
{
read(a), read(b), read(x); res = (ll)T.query_path(a, b).val;
if(res) printf("%lld\n", x / res);
else puts("0");
}
else
{
read(a), read(x);
T.update_point(a, x);
}
}
return 0;
}

这板子我还记得怎么写,宝刀未老啊。

题解:CF593D Happy Tree Party的更多相关文章

  1. 【题解】Digit Tree

    [题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. ...

  2. 【题解】[P4178 Tree]

    [题解]P4178 Tree 一道点分治模板好题 不知道是不是我见到的题目太少了,为什么这种题目都是暴力开值域的桶QAQ?? 问点对,考虑点分治吧.直接用值域树状数组开下来,统计的时候直接往树状数组里 ...

  3. leetcode 题解:Binary Tree Inorder Traversal (二叉树的中序遍历)

    题目: Given a binary tree, return the inorder traversal of its nodes' values. For example:Given binary ...

  4. [LeetCode 题解]: Flatten Binary Tree to Linked List

    Given a binary tree, flatten it to a linked list in-place. For example,Given 1 / \ 2 5 / \ \ 3 4 6 T ...

  5. leetcode题解:Construct Binary Tree from Preorder and Inorder Traversal (根据前序和中序遍历构造二叉树)

    题目: Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume t ...

  6. CF593D Happy Tree Party(不用树剖)

    题面 题解 我们发现,对于除法有效的xi最小为2,yi最多除log次就会变成0,所以我们可以每次找路径上下一个>=2的xi,暴力除,当发现y=0时就停止 于是我们维护每个点向上走一直走到根最近的 ...

  7. LeetCode题解之Binary Tree Right Side View

    1.题目描述 2.问题分析 使用层序遍历 3.代码 vector<int> v; vector<int> rightSideView(TreeNode* root) { if ...

  8. LeetCode题解之Binary Tree Pruning

    1.题目描述 2.问题分析 使用递归 3.代码 TreeNode* pruneTree(TreeNode* root) { if (root == NULL) return NULL; prun(ro ...

  9. LeetCode题解Maximum Binary Tree

    1.题目描述 2.分析 找出最大元素,然后分割数组调用. 3.代码 TreeNode* constructMaximumBinaryTree(vector<int>& nums) ...

随机推荐

  1. 为系统增加删除swap空间

    增加 1.创建/home/swap这么一个分区文件.文件大小是512000个block,一般情况下1个block为1k,所以这里空间是512M,这个空间大小自己随意定义. dd if=/dev/zer ...

  2. Redis 6.0.8 紧急发布,请尽快升级!

    大家周末愉快啊,今天分享一则重要通知. Redis 6.0.8 于 2020/9/10 日晚紧急发布!!! 可以看到这是一个紧急更新版本,使用了 Redis 6.0.7 Sentinel(哨兵)以及 ...

  3. 执行./install.sh时报错-bash: ./install.sh: /bin/bash^M: 坏的解释器: 没有那个文件或目录

    百度解释说是因为这个文件在windows下编辑过,windows下每一行的结尾是\n\r, 而linux下每一行结尾是\n,所以只需要删除这个文件中的\r字符就可以了sed -i 's/\r$//' ...

  4. JVM运行时数据区--方法区

    运行时数据区结构图(温习): 堆.栈.方法区的交互关系 方法区的理解 方法区(Method Area)与Java堆一样,是各个线程共享的内存区域 方法区在JVM启动时就会被创建,并且它的实际的物理内存 ...

  5. JVM关于GC的日志分析

    通过阅读GC日志,我们可以了解Java虛拟机内存分配与回收策略.内存分配与垃圾回收的参数列表 一XX: +PrintGC 输出Gc日志.类似: 一verbose:gc 一XX: +PrintGCDet ...

  6. 高可用集群之keepalived+lvs实战

    keepalived简介 lvs在我之前的博客<高负载集群实战之lvs负载均衡-技术流ken>中已经进行了详细的介绍和应用,在这里就不再赘述.这篇博文将把lvs与keepalived相结合 ...

  7. archaius(3) 配置管理器

    基于上一节介绍的配置源,我们来继续了解配置管理器.配置源只是抽象了配置的获取来源,配置管理器是基于配置源的基础上对这些配置项进行管理.配置管理器的主要功能是将配置从目标位置加载到内存中,并且管理内存配 ...

  8. RXJAVA源码之多线程

    在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件:在哪个线程生产事件,就在哪个线程消费事件.如果需要切换线程,就需要用到 ...

  9. 快速了解前端开发HTML的正确姿势

    摘要:web前端开发(也称为客户端开发)主要是通过html,CSS和JavaScript等前端技术,实现网站在客服端的正确显示及交互功能. 一.web标准介绍 web标准: w3c:万维网联盟组织,用 ...

  10. python学习笔记1之-python简介及其环境安装

    python学习笔记之-python简介及其环境安装 最近几年python之火不用多说,最近开始利用时间自学python,在学习的过程中,按照自己的思路和理解记录下学习的过程,并分享出来,如果正好你也 ...