CF 593D

题目: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:

#include <bits/stdc++.h>

using namespace std;

const int N = 200010;

int ecnt, fa[N], to[N], head[N], dep[N];
long long g[N];

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[N];

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?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值