Codechef Dynamic GCD
就是考虑维护链上 gcd \gcd gcd 和链加。我们先考虑这个东西放到序列上怎么做,首先进行差分,之后因为 gcd \gcd gcd 是不变的,但是区间加可以直接变成了单点修改用线段树进行维护即可。
对于树上的情况,我们直接使用树链剖分进行分成若干条链进行计算。
具体来说我们考虑对于一条链 u , v , f a u = v u, v, fa_u = v u,v,fau=v,我们让节点 u u u 的值变成 a v − a u a_v - a_u av−au 即可。对于链头的情况我们直接作为原来的值即可。
但是会有一个问题,如果我们一条链没有被使用完成我们就需要知道最上面的那个值。
对于这个我们只需要维护一下被加的值即可,为了方便使用了标记永久化。
一些细节:
- 根据我们差分的定义,对于一个节点 u u u 增加了 c c c 的时候,其单点维护的 gcd \gcd gcd 是要 − c - c −c 的,其儿子是要 + c + c +c 的。当然对于 u = t o p u u = \tt{top}_u u=topu 的情况例外。
- 我们进行最终计算答案的时候不要忘记计算最上面一个点的贡献,也不要多计算。
#include <bits/stdc++.h>
using namespace std;
//#define Fread
//#define Getmod
#ifdef Fread
char buf[1 << 21], *iS, *iT;
#define gc() (iS == iT ? (iT = (iS = buf) + fread (buf, 1, 1 << 21, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
#define getchar gc
#endif // Fread
template <typename T>
void r1(T &x) {
x = 0;
char c(getchar());
int f(1);
for(; c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(; '0' <= c && c <= '9';c = getchar()) x = (x * 10) + (c ^ 48);
x *= f;
}
template <typename T,typename... Args> inline void r1(T& t, Args&... args) {
r1(t); r1(args...);
}
#ifdef Getmod
const int mod = 1e9 + 7;
template <int mod>

本文详细解析了如何解决Codechef上的动态GCD问题。通过差分操作和线段树维护区间gcd,结合树链剖分处理树结构的数据。在树链剖分的基础上,针对每条链进行gcd的更新,并利用标记永久化处理未完全使用的链。算法实现中需要注意节点值的增减以及避免计算误差。
最低0.47元/天 解锁文章
6264

被折叠的 条评论
为什么被折叠?



