CF 593D
2015-11-06 12:59
423 查看
题目:Happy
Tree Party
有一棵树,每条边有一个值,要求支持两种操作:1. 一条边 pi 的值有 xpi 改为 c , c < xpi 2. 给两个点 u, v 和一个初始值 y,要求从 u 沿最短路旅行到 v, 每经过一条边 i, y /= xi问 y 的值。
可以发现: y 最终的值和除法的顺序无关, 那么答案就是 y / Π xi,到这里就可以发现这题可以用树链剖分做了,遇到爆 LL 的时候特殊处理下就好了。
但是,我们会发现题目给的条件有一个没用上,就是 c < xpi 。因为 y < 1e18 < 2 ^ 64 所以当经过最多64条权值>1的边之后,y就变为0了, 那么实际上每次询问最多需要对权值>1的边做除法64次就够了,于是我们可以将连续的权值为 1 的边看成一条边, 对每次询问, 由下至上遍历至LCA即可。
AC code:
顺便扔一道同类题:Can you answer these queries?
Tree Party
有一棵树,每条边有一个值,要求支持两种操作:1. 一条边 pi 的值有 xpi 改为 c , c < xpi 2. 给两个点 u, v 和一个初始值 y,要求从 u 沿最短路旅行到 v, 每经过一条边 i, y /= xi问 y 的值。
可以发现: y 最终的值和除法的顺序无关, 那么答案就是 y / Π xi,到这里就可以发现这题可以用树链剖分做了,遇到爆 LL 的时候特殊处理下就好了。
但是,我们会发现题目给的条件有一个没用上,就是 c < xpi 。因为 y < 1e18 < 2 ^ 64 所以当经过最多64条权值>1的边之后,y就变为0了, 那么实际上每次询问最多需要对权值>1的边做除法64次就够了,于是我们可以将连续的权值为 1 的边看成一条边, 对每次询问, 由下至上遍历至LCA即可。
AC code:
#include <bits/stdc++.h> using namespace std; const int N = 200010; int ecnt, fa , to , head , dep ; long long g ; struct Edge { int pre, idx, to; long long cost; Edge(int p = 0, int i = 0, int t = 0, long long c = 0) : pre(p), idx(i), to(t), cost(c) {} } edge[N << 1]; void link(int u, int v, int id, long long w) { edge[ecnt] = Edge(head[u], id, v, w); head[u] = ecnt++; } void dfs(int u, int d) { dep[u] = d; for (int i = head[u]; ~ i; i = edge[i].pre) { int v = edge[i].to; if (v == fa[u]) continue; fa[v] = u; g[v] = edge[i].cost; to[edge[i].idx] = v; dfs(v, d + 1); } } int f ; int Find(int u) { return ~ f[u] ? f[u] = Find(f[u]) : u; } void up(int u) { f[u] = Find(fa[u]); } long long get(int u, int v, long long w) { u = Find(u); v = Find(v); while (u != v) { if (dep[u] < dep[v]) u ^= v ^= u ^= v; w /= g[u]; u = Find(fa[u]); if (w == 0) return 0; } return w; } int main() { int n, m; scanf("%d %d", &n, &m); memset(head, 0xff, (n + 1) * sizeof (int)); for (int i = 1; i < n; i++) { int u, v; long long w; scanf("%d %d %I64d", &u,& v, &w); link(u, v, i, w); link(v, u, i, w); } dfs(1, 0); memset(f, 0xff, (n + 1) * sizeof (int)); for (int i = 1; i <= n; i++) { if (g[i] == 1) up(i); } while (m--) { int t, u, v; long long w; scanf("%d %d", &t, &u); if (t == 1) { scanf("%d %I64d", &v, &w); printf("%I64d\n", get(u, v, w)); } else { scanf("%I64d", &w); v = to[u]; g[v] = w; if (w == 1) up(v); } } }
顺便扔一道同类题:Can you answer these queries?
相关文章推荐
- window.name==window['name']
- 对话 UNIX: 探察管道
- activemq和jms是种什么关系
- 内存管理
- 在Android上修改读取IMEI码的方法
- uboot 中SECTIONS 详解
- iOS ---反向传值 协议传值
- 状态栏沉浸
- 学习pox心得
- 设置文本框不可编辑
- Web工程阶段性总结
- 贪心 Codeforces584C Marina and Vasya
- jstack和线程dump分析
- javascript设计模式-装饰着模式
- 探索A@1db9742
- Android Studio 1.3/1.4 无法更新下载Android NDK:install failed please check your network
- 百度搜索软件名称时提供的快速下载的软件可能有病毒或非官方
- 机器学习
- 往前往后推时间(排除工作日和节假日)
- C++ string操作汇总