树链剖分+差分

直接区间加显然是不行的,由于gcd(a,b,c)=gcd(a,a-b,b-c),那么我们对这些数差分,然后就变成单点修改。原本以为这道题很简单,没想到这么麻烦,就膜了发代码。

首先我们考虑如何在树上差分序列,每个节点有很多个儿子,如果把每个儿子都修改一下就GG了,其实我们可以这个样子,我们只维护重儿子的差分值,但是如果从轻儿子爬上来呢?我们就把父亲节点单独取出来做gcd,也就是我们再维护一个原序列的值,每次爬重链的时候就把链下面最深的点用原序列中的值来求,这样就可以了。然后还有各种修改,树状数组维护原序列比较简单,就是一个差分序列,但是树上要注意一些,每次要修改链头和链底的重儿子,注意这里和平常的差分不太一样,这里是父亲和儿子之间的差分,如果是一条被修改的路径那么就抵消,否则就差分,感觉还是挺巧妙的。

#include<bits/stdc++.h>
using namespace std;
const int N = 5e4 + ;
inline int rd()
{
int x = , f = ; char c = getchar();
while(c < '' || c > '') { if(c == '-') f = -; c = getchar(); }
while(c >= '' && c <= '') { x = x * + c - ''; c = getchar(); }
return x * f;
}
int n, m, cnt, dfs_clock;
int head[N], a[N], fa[N], dfn[N], top[N], son[N], dep[N], size[N];
struct edge {
int nxt, to;
} e[N << ];
int gcd(int a, int b)
{
return !b ? a : gcd(b, a % b);
}
void link(int u, int v)
{
e[++cnt].nxt = head[u];
head[u] = cnt;
e[cnt].to = v;
}
void dfs(int u, int last)
{
size[u] = ;
for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last)
{
dep[e[i].to] = dep[u] + ;
fa[e[i].to] = u;
dfs(e[i].to, u);
size[u] += size[e[i].to];
if(size[e[i].to] > size[son[u]]) son[u] = e[i].to;
}
}
void dfs(int u, int last, int anc)
{
dfn[u] = ++dfs_clock;
top[u] = anc;
if(son[u]) dfs(son[u], u, anc);
for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last && e[i].to != son[u]) dfs(e[i].to, u, e[i].to);
}
namespace BIT
{
int tr[N];
void update(int x, int d)
{
if(!x) return;
for(; x <= n; x += x & -x) tr[x] += d;
}
int query(int x)
{
int ret = ;
for(; x; x -= x & -x) ret += tr[x];
return ret;
}
}
namespace Segment_Tree
{
int t[N << ];
void build(int l, int r, int x)
{
if(l == r)
{
t[x] = a[l];
return;
}
int mid = (l + r) >> ;
build(l, mid, x << );
build(mid + , r, x << | );
t[x] = gcd(t[x << ], t[x << | ]);
}
void update(int l, int r, int x, int p, int d)
{
if(l == r)
{
t[x] += d;
return;
}
int mid = (l + r) >> ;
if(p <= mid) update(l, mid, x << , p, d);
else update(mid + , r, x << | , p, d);
t[x] = gcd(t[x << ], t[x << | ]);
}
int query(int l, int r, int x, int a, int b)
{
if(l > b || r < a) return ;
if(l >= a && r <= b) return t[x];
int mid = (l + r) >> ;
return gcd(query(l, mid, x << , a, b), query(mid + , r, x << | , a, b));
}
}
namespace Operation
{
int ask(int u, int v)
{
int ret = ;
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]]) swap(u, v);
ret = gcd(ret, gcd(Segment_Tree :: query(, n, , dfn[top[u]] + , dfn[u]), BIT :: query(dfn[top[u]])));
u = fa[top[u]];
}
if(dfn[u] < dfn[v]) swap(u, v);
return abs(gcd(ret, gcd(Segment_Tree :: query(, n, , dfn[v] + , dfn[u]), BIT :: query(dfn[v]))));
}
void change(int u, int v, int d)
{
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]]) swap(u, v);
Segment_Tree :: update(, n, , dfn[top[u]], -d);
if(son[u]) Segment_Tree :: update(, n, , dfn[son[u]], d);
BIT :: update(dfn[top[u]], d);
BIT :: update(dfn[u] + , -d);
u = fa[top[u]];
}
if(dfn[u] < dfn[v]) swap(u, v);
Segment_Tree :: update(, n, , dfn[v], -d);
if(son[u]) Segment_Tree :: update(, n, , dfn[son[u]], d);
BIT :: update(dfn[v], d);
BIT :: update(dfn[u] + , -d);
}
}
int main()
{
n = rd();
for(int i = ; i < n; ++i)
{
int u = rd() + , v = rd() + ;
link(u, v);
link(v, u);
}
dfs(, );
dfs(, , );
for(int i = ; i <= n; ++i)
{
a[dfn[i]] = rd();
BIT :: update(dfn[i], a[dfn[i]]);
BIT :: update(dfn[i] + , -a[dfn[i]]);
}
for(int i = n; i; --i) a[i] = a[i - ] - a[i];
Segment_Tree :: build(, n, );
m = rd();
while(m--)
{
char s[];
scanf("%s", s);
int u = rd() + , v = rd() + , d;
if(s[] == 'F') printf("%d\n", Operation :: ask(u, v));
if(s[] == 'C')
{
d = rd();
Operation :: change(u, v, d);
}
}
return ;
}

Dynamic Gcd的更多相关文章

  1. codechef Dynamic GCD [树链剖分 gcd]

    Dynamic GCD 题意:一棵树,字词树链加,树链gcd 根据\(gcd(a,b)=gcd(a,a-b)\) 得到\(gcd(a_1, a_2, ..., a_i) = gcd(a_1, a_1- ...

  2. CodeChef DGCD Dynamic GCD

    CodeChef题面 Time limit 210 ms Code length Limit //内存限制也不说一下,真是的-- 50000 B OS Linux Language limit C, ...

  3. CodeChef Dynamic GCD

    嘟嘟嘟vjudge 我今天解决了一个历史遗留问题! 题意:给一棵树,写一个东西,支持一下两种操作: 1.\(x\)到\(y\)的路径上的每一个点的权值加\(d\). 2.求\(x\)到\(y\)路径上 ...

  4. CC DGCD:Dynamic GCD——题解

    https://vjudge.net/problem/CodeChef-DGCD https://www.codechef.com/problems/DGCD 题目大意: 给一颗带点权的树,两个操作: ...

  5. scau 2015寒假训练

    并不是很正规的.每个人自愿参与自愿退出,马哥找题(马哥超nice么么哒). 放假第一周与放假结束前一周 2015-01-26 http://acm.hust.edu.cn/vjudge/contest ...

  6. BZOJ 5028 小z的加油站

    bzoj链接 Time limit 10000 ms Memory limit 262144 kB OS Linux 感想 树上动态gcd的第二题也好了. [x] BZOJ 2257 [JSOI200 ...

  7. 洛谷 P4571 BZOJ 2257 [JSOI2009]瓶子和燃料

    bzoj题目链接 上面hint那里是选择第2个瓶子和第3个瓶子 Time limit 10000 ms Memory limit 131072 kB OS Linux Source Jsoi2009 ...

  8. Cache index coloring for virtual-address dynamic allocators

    A method for managing a memory, including obtaining a number of indices and a cache line size of a c ...

  9. 动态规划系列(零)—— 动态规划(Dynamic Programming)总结

    动态规划三要素:重叠⼦问题.最优⼦结构.状态转移⽅程. 动态规划的三个需要明确的点就是「状态」「选择」和「base case」,对应着回溯算法中走过的「路径」,当前的「选择列表」和「结束条件」. 某种 ...

随机推荐

  1. C++中sizeof(struct)怎么计算?(转)

    struct为空时,大小为1. 1. sizeof应用在结构上的情况 请看下面的结构: struct MyStruct { double dda1; char dda; int type; }; 对结 ...

  2. 网络通讯框架MINA和XSCOCKET的简单比较

    http://www.blogjava.net/ghostdog/archive/2008/06/10/MinaVsXsocket.html实在无聊,考虑把当前应用的通讯模式由http移植为socke ...

  3. Spring Boot 测试时的日志级别

    1.概览 该教程中,我将向你展示:如何在测试时设置spring boot 日志级别.虽然我们可以在测试通过时忽略日志,但是如果需要诊断失败的测试,选择正确的日志级别是非常重要的. 2.日志级别的重要性 ...

  4. kubernetes之pod中断

    系列目录 目标读者: 想要构建高可用应用的应用所有者,因此需要知道pod会发生哪些类型的中断 想要执行自动化(比如升级和自动扩容)的集群管理员. 自愿和非自愿的中断 pod不会自动消息,除非有人(可能 ...

  5. Canvas学习笔记——动画中摩擦力的运用

    摩擦力是与物体运动方向相反的力.我们在处理物体运动时,常把物体分解水平(X轴)方向和竖直(Y轴)方向的运动(比如平抛运动),但在处理摩擦力时,如果把摩擦力分解为X轴和Y轴上的阻力,就会出现某条轴上速度 ...

  6. linux新建文件和文件夹命令

    1.touch命令 touch命令用来修改文件的访问时间.修改时间.如果没有指定时间,则将文件时间属性改为当前时间. 当指定文件不存在,touch命令变为创建该文件. 语法: touch [-acm] ...

  7. live555 RTSP推送到Darwin出现404错误的解决

    我们将Darwin部署到公网,接收live555 RTSP/RTP推送的时候,经常会出现在SETUP步骤Darwin返回404错误,经过查找原因,主要是Darwin对live555推送的sdp信息中的 ...

  8. EasyDarwin开源平台直播架构

    Created with Raphaël 2.1.0ClientClientEasyCMSEasyCMSEasyCameraEasyCameraEasyDarwinEasyDarwin请求设备列表设备 ...

  9. 6.5.1.3 Caching SHA-2 Pluggable Authentication

    MySQL :: MySQL 8.0 Reference Manual :: 6.5.1.3 Caching SHA-2 Pluggable Authentication https://dev.my ...

  10. C++编程规范纲要要点小结

    这是一本好书, 可以让你认清自己对C++的掌握程度. 看完之后,给自己打分,我对C++了解多少? 答案是不足20分. 对于我自己是理所当然的问题, 就不提了, 记一些有启发的条目和细节: (*号表示不 ...