https://vjudge.net/problem/CodeChef-DGCD

https://www.codechef.com/problems/DGCD

题目大意:

给一颗带点权的树,两个操作:

1.将两点间最短路上的点权+d

2.查询两点间最短路上的点权的GCD

显然又是树链剖分,点这里看树链剖分原理

但是我们发现一个问题,我们虽然可以建立线段树维护GCD,但是没有办法处理区间修改问题。

我们考虑更相减损之术的原理,两数做差后的结果和小数的GCD=原来的GCD。

所以我们在维护单点权值的同时维护相邻点权的差值,则GCD(区间内所有相邻点权差的GCD,区间首位点权)就是我们要查的值。

虽然这么说很简单,但是有很多具体细节,大体比较难解决的比如:

1.修改区间的时候,单点权值要用lazy标记维护,而相邻点权的差值就单点修改两次(注意:有些情况下也可能只有一次)即可。

2.询问的时候,单点权值单点查询即可,相邻点权的差值区间查询,注意区间长度为点数-1,也就是说我们可能会碰到空区间,特判掉。

其余具体操作请看代码。

  1. #include<cstdio>
  2. #include<iostream>
  3. using namespace std;
  4. const int N=;
  5. const int INF=;
  6. /*============================**
  7. *************基本操作************
  8. **============================*/
  9. inline int read(){
  10. int X=,w=;char ch=;
  11. while(ch<''||ch>''){w|=ch=='-';ch=getchar();}
  12. while(ch>=''&&ch<='')X=(X<<)+(X<<)+(ch^),ch=getchar();
  13. return w?-X:X;
  14. }
  15. struct node{
  16. int to;
  17. int nxt;
  18. }edge[*N];
  19. struct tree{
  20. int lazy;
  21. int d;
  22. int v;
  23. }t[*N];
  24. int head[N],cnt=,n;
  25. inline void add(int u,int v){
  26. cnt++;
  27. edge[cnt].to=v;
  28. edge[cnt].nxt=head[u];
  29. head[u]=cnt;
  30. return;
  31. }
  32. inline int abs(int x){
  33. return x>?x:-x;
  34. }
  35. int gcd(int x,int y){
  36. return y?gcd(y,x%y):abs(x);
  37. }
  38. int fa[N],dep[N],size[N],son[N],top[N],pos[N],idx[N];
  39. int val[N];
  40. /*============================**
  41. *************树链剖分************
  42. **============================*/
  43. void dfs1(int u){
  44. size[u]=;
  45. for(int i=head[u];i;i=edge[i].nxt){
  46.    int v=edge[i].to;
  47.    if(v==fa[u])continue;
  48.    fa[v]=u;dep[v]=dep[u]+;
  49.    dfs1(v);
         size[u]+=size[v];
  50.    if(!son[u]||size[v]>size[son[u]])son[u]=v;
  51. }
  52. return;
  53. }
  54. int tot;
  55. void dfs2(int u,int anc){
  56.    tot++;
  57.    pos[u]=tot;
  58.    idx[tot]=u;
  59.    top[u]=anc;
  60.    if(!son[u])return;
  61.    dfs2(son[u],anc);
  62.    for(int i=head[u];i;i=edge[i].nxt){
  63.    int v=edge[i].to;
  64.    if(v==fa[u]||v==son[u])continue;
  65.    dfs2(v,v);
  66. }
  67. return;
  68. }
  69. inline void init(){
  70. dfs1();
  71. top[]=idx[]=pos[]=;
  72. tot=;
  73. dfs2(,);
  74. return;
  75. }
  76. /*============================**
  77. ************传递lazy************
  78. **============================*/
  79. inline void pushdown(int a,bool is_leaf){
  80. if(is_leaf){
  81.    t[a].v+=t[a].lazy;
  82. }else{
  83.    t[a*].lazy+=t[a].lazy;
  84.    t[a*+].lazy+=t[a].lazy;
  85. }
  86. t[a].lazy=;
  87. return;
  88. }
  89. /*============================**
  90. *************建树操作************
  91. **============================*/
  92. void build(int a,int l,int r){
  93. if(l==r){
  94.    t[a].v=val[idx[l]];
  95.    t[a].d=val[idx[l]]-val[idx[l-]];
  96.    return;
  97. }
  98. int mid=(l+r)>>;
  99. build(a*,l,mid);
  100. build(a*+,mid+,r);
  101. t[a].d=gcd(t[a*].d,t[a*+].d);
  102. return;
  103. }
  104. /*============================**
  105. *************查询操作************
  106. **============================*/
  107. int point_query(int a,int l,int r,int k){
  108. pushdown(a,(l==r));
  109. if(l==r){
  110.    return t[a].v;
  111. }
  112. int mid=(l+r)>>;
  113. if(k<=mid)return point_query(a*,l,mid,k);
  114. return point_query(a*+,mid+,r,k);
  115. }
  116. int range_query(int a,int l,int r,int l1,int r1){
  117. if(l1>r1)return ;
  118. if(r<l1||r1<l)return ;
  119. if(l1<=l&&r<=r1){
  120.    return t[a].d;
  121. }
  122. int mid=(l+r)>>;
  123. return gcd(range_query(a*,l,mid,l1,r1),range_query(a*+,mid+,r,l1,r1));
  124. }
  125. int path_query(int u,int v){
  126. if(top[u]!=top[v]){
  127.    if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;}
  128.    if(top[u]!=u)
  129.    return gcd(path_query(fa[top[u]],v),gcd(range_query(,,n,pos[son[top[u]]],pos[u]),point_query(,,n,pos[top[u]])));
  130.    return gcd(path_query(fa[top[u]],v),point_query(,,n,pos[top[u]]));
  131. }
  132. if(dep[u]>dep[v]){int t=u;u=v;v=t;}
  133. if(u!=v)
  134.    return gcd(point_query(,,n,pos[u]),range_query(,,n,pos[son[u]],pos[v]));
  135. return point_query(,,n,pos[u]);
  136. }
  137. /*============================**
  138. *************修改操作************
  139. **===========================**/
  140. void point_modi(int a,int l,int r,int k,int c){
  141. if(l==r){
  142.    t[a].d+=c;
  143.    return;
  144. }
  145. int mid=(l+r)>>;
  146. if(k<=mid)point_modi(a*,l,mid,k,c);
  147. else point_modi(a*+,mid+,r,k,c);
  148. t[a].d=gcd(t[a*].d,t[a*+].d);
  149. return;
  150. }
  151. void range_modi(int a,int l,int r,int l1,int r1,int v){
  152. if(r1<l||r<l1)return;
  153. pushdown(a,(l==r));
  154. if(l1<=l&&r<=r1){
  155.    t[a].lazy+=v;
  156.    return;
  157. }
  158. int mid=(l+r)>>;
  159. range_modi(a*,l,mid,l1,r1,v);
  160. range_modi(a*+,mid+,r,l1,r1,v);
  161. return;
  162. }
  163. void path_modi(int u,int v,int c){
  164. if(top[u]!=top[v]){
  165.   if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;}
  166.   point_modi(,,n,pos[top[u]],c);
  167.    if(son[u]!=u)point_modi(,,n,pos[son[u]],-c);
  168.    range_modi(,,n,pos[top[u]],pos[u],c);
  169.    path_modi(fa[top[u]],v,c);
  170.    return;
  171. }
  172. if(dep[u]>dep[v]){int t=u;u=v;v=t;}
  173. point_modi(,,n,pos[u],c);
  174. if(son[v])point_modi(,,n,pos[son[v]],-c);
  175. range_modi(,,n,pos[u],pos[v],c);
  176. return;
  177. }
  178. /*============================**
  179. *************主程序段************
  180. **============================*/
  181. int main(){
  182. n=read();
  183. for(int i=;i<=n;i++){
  184.    int u=read()+;
  185.   int v=read()+;
  186.   add(u,v);
  187.    add(v,u);
  188. }
  189. for(int i=;i<=n;i++)val[i]=read();
  190. init();
  191. build(,,n);
  192. int q=read();
  193. while(q--){
  194. char op=;
  195. while(op!='F'&&op!='C')op=getchar();
  196.   if(op=='C'){
  197.    int a=read()+;
  198.    int b=read()+;
  199.    int c=read();
  200.    path_modi(a,b,c);
  201.   }else{
  202.    int a=read()+;
  203.    int b=read()+;
  204.    printf("%d\n",path_query(a,b));
  205.    }
  206. }
  207. return ;
  208. }

CC DGCD:Dynamic GCD——题解的更多相关文章

  1. CodeChef DGCD Dynamic GCD

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

  2. 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- ...

  3. HDU5726:GCD——题解

    题目:hdu的5726 (我原博客的东西,正好整理过来,属于st表裸题) (可以看出我当时有多么的菜--) 这道题写了一遍,然而蒟蒻的我的时间爆炸了-- 于是看了一下学长的代码(顺便在此处%一下学长) ...

  4. 洛谷 P2568 GCD 题解

    原题链接 庆祝一下:数论紫题达成成就! 第一道数论紫题.写个题解庆祝一下吧. 简要题意:求 \[\sum_{i=1}^n \sum_{j=1}^n [gcd(i,j)==p] \] 其中 \(p\) ...

  5. CodeChef Dynamic GCD

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

  6. BZOJ2820:YY的GCD——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2820 Description 神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x& ...

  7. BZOJ1901:Zju2112 Dynamic Rankings——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1901 Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序 ...

  8. Dynamic Gcd

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

  9. CH 4302 Interval GCD 题解

    题意 给定一个长度为N的数列A,以及M条指令 (N≤5* 10^5, M<=10^5),每条指令可能是以下两种之一: "C l r d",表示把 A[l],A[l+1],-, ...

随机推荐

  1. json模块使用总结——Python

    # 原创文章,未经允许请勿转载 通过Python的json模块,可以将字符串形式的json数据转化为字典,也可以将Python中的字典数据转化为字符串形式的json数据. 之前使用这个模块时,都是随用 ...

  2. Objective-C NSString基本使用 类方法 self关键字

    NSString基本使用 #import <Foundation/Foundation.h> int main() { //最简单的创建字符串的方式 NSString *str = @&q ...

  3. word record 01

    词义默认包括发音 coil /kɔɪl/ 发音(kuo you) collage /kə'lɑʒ/ 发音(ke la shi) colleague /'kɑliɡ/ 发音 (ka li ge) com ...

  4. C#使用EF连接PGSql数据库

    前言 由于项目需要,使用到了PGSql数据库,说实话这是第一次接触并且听说PGSql(PostgreSQL)关系型数据库,之前一直使用的都是SqlServer,一头雾水的各种找资源,终于将PGSql与 ...

  5. 接口文档神器--apiui的使用

    接口开发,最麻烦的就是写文档了,曾经我也因为写接口文档苦不堪言:自从使用了apiui接口文档神器,工作效率和文档清晰得到了不止一个档次的提升. 下面介绍一下这个神器的使用: 把文件下载下来,放在网站根 ...

  6. python常用命令—终端安装win32的两种方法

    1, pip install pywin32 2, pip install pypiwin32

  7. crt0.S(_main)代码分析

    crt0,S(_main)代码分析 --- 1. 设置sp寄存器地址 //设置SP栈指针 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG ...

  8. H5页面 绝对定位元素被 软键盘弹出时顶起

    H5页面 绝对定位元素被 软键盘弹出时顶起 在h5页面开发的过程中,我们可能会遇到下面这个问题,当页面中有输入框的时候,系统自带的软盘会把按钮挤出原来的位置.那么我们该怎么解决呢?下面列出一下的方法: ...

  9. 下载 编译 Android源代码 和 Android kernel源代码

    下载Android源码简要流程 : a. 获取repo文件: curl http://commondatastorage.googleapis.com/git-repo-downloads/repo ...

  10. Java Class Object

    Object类 它是所有类的基类. public class Person { } //实际上是 public class Person extends Object { } Object类的方法 t ...