您的位置:首页 > 其它

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:

#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?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: