zoukankan      html  css  js  c++  java
  • CC DGCD:Dynamic GCD——题解

    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,也就是说我们可能会碰到空区间,特判掉。

    其余具体操作请看代码。

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int N=50001;
    const int INF=2147483647;
    /*============================**
    *************基本操作************
    **============================*/
    inline int read(){
        int X=0,w=0;char ch=0;
        while(ch<'0'||ch>'9'){w|=ch=='-';ch=getchar();}
        while(ch>='0'&&ch<='9')X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int to;
        int nxt;
    }edge[2*N];
    struct tree{
        int lazy;
        int d;
        int v;
    }t[4*N];
    int head[N],cnt=0,n;
    inline void add(int u,int v){
        cnt++;
        edge[cnt].to=v;
        edge[cnt].nxt=head[u];
        head[u]=cnt;
        return;
    }
    inline int abs(int x){
        return x>0?x:-x;
    }
    int gcd(int x,int y){
        return y?gcd(y,x%y):abs(x);
    }
    int fa[N],dep[N],size[N],son[N],top[N],pos[N],idx[N];
    int val[N];
    /*============================**
    *************树链剖分************
    **============================*/
    void dfs1(int u){
        size[u]=1;
        for(int i=head[u];i;i=edge[i].nxt){
          int v=edge[i].to;
          if(v==fa[u])continue;
          fa[v]=u;dep[v]=dep[u]+1;
          dfs1(v);
         size[u]
    +=size[v];    if(!son[u]||size[v]>size[son[u]])son[u]=v; } return; } int tot; void dfs2(int u,int anc){    tot++;    pos[u]=tot;    idx[tot]=u;    top[u]=anc;    if(!son[u])return;    dfs2(son[u],anc);    for(int i=head[u];i;i=edge[i].nxt){    int v=edge[i].to;    if(v==fa[u]||v==son[u])continue;    dfs2(v,v); } return; } inline void init(){ dfs1(1); top[1]=idx[1]=pos[1]=1; tot=1; dfs2(1,1); return; } /*============================** ************传递lazy************ **============================*/ inline void pushdown(int a,bool is_leaf){ if(is_leaf){    t[a].v+=t[a].lazy; }else{    t[a*2].lazy+=t[a].lazy;    t[a*2+1].lazy+=t[a].lazy; } t[a].lazy=0; return; } /*============================** *************建树操作************ **============================*/ void build(int a,int l,int r){ if(l==r){    t[a].v=val[idx[l]];    t[a].d=val[idx[l]]-val[idx[l-1]];    return; } int mid=(l+r)>>1; build(a*2,l,mid); build(a*2+1,mid+1,r); t[a].d=gcd(t[a*2].d,t[a*2+1].d); return; } /*============================** *************查询操作************ **============================*/ int point_query(int a,int l,int r,int k){ pushdown(a,(l==r)); if(l==r){    return t[a].v; } int mid=(l+r)>>1; if(k<=mid)return point_query(a*2,l,mid,k); return point_query(a*2+1,mid+1,r,k); } int range_query(int a,int l,int r,int l1,int r1){ if(l1>r1)return 0; if(r<l1||r1<l)return 0; if(l1<=l&&r<=r1){    return t[a].d; } int mid=(l+r)>>1; return gcd(range_query(a*2,l,mid,l1,r1),range_query(a*2+1,mid+1,r,l1,r1)); } int path_query(int u,int v){ if(top[u]!=top[v]){    if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;}    if(top[u]!=u)    return gcd(path_query(fa[top[u]],v),gcd(range_query(1,1,n,pos[son[top[u]]],pos[u]),point_query(1,1,n,pos[top[u]])));    return gcd(path_query(fa[top[u]],v),point_query(1,1,n,pos[top[u]])); } if(dep[u]>dep[v]){int t=u;u=v;v=t;} if(u!=v)    return gcd(point_query(1,1,n,pos[u]),range_query(1,1,n,pos[son[u]],pos[v])); return point_query(1,1,n,pos[u]); } /*============================** *************修改操作************ **===========================**/ void point_modi(int a,int l,int r,int k,int c){ if(l==r){    t[a].d+=c;    return; } int mid=(l+r)>>1; if(k<=mid)point_modi(a*2,l,mid,k,c); else point_modi(a*2+1,mid+1,r,k,c); t[a].d=gcd(t[a*2].d,t[a*2+1].d); return; } void range_modi(int a,int l,int r,int l1,int r1,int v){ if(r1<l||r<l1)return; pushdown(a,(l==r)); if(l1<=l&&r<=r1){    t[a].lazy+=v;    return; } int mid=(l+r)>>1; range_modi(a*2,l,mid,l1,r1,v); range_modi(a*2+1,mid+1,r,l1,r1,v); return; } void path_modi(int u,int v,int c){ if(top[u]!=top[v]){   if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;}   point_modi(1,1,n,pos[top[u]],c);    if(son[u]!=u)point_modi(1,1,n,pos[son[u]],-c);    range_modi(1,1,n,pos[top[u]],pos[u],c);    path_modi(fa[top[u]],v,c);    return; } if(dep[u]>dep[v]){int t=u;u=v;v=t;} point_modi(1,1,n,pos[u],c); if(son[v])point_modi(1,1,n,pos[son[v]],-c); range_modi(1,1,n,pos[u],pos[v],c); return; } /*============================** *************主程序段************ **============================*/ int main(){ n=read(); for(int i=2;i<=n;i++){    int u=read()+1;   int v=read()+1;   add(u,v);    add(v,u); } for(int i=1;i<=n;i++)val[i]=read(); init(); build(1,1,n); int q=read(); while(q--){ char op=0; while(op!='F'&&op!='C')op=getchar();   if(op=='C'){    int a=read()+1;    int b=read()+1;    int c=read();    path_modi(a,b,c);   }else{    int a=read()+1;    int b=read()+1;    printf("%d ",path_query(a,b));    } } return 0; }
  • 相关阅读:
    跨域问题----CORS
    java设计模式--简单工厂模式
    vue+java后台通信报403,cors解决跨域问题(该贴说的不是很清楚,不过大概如此,可再去网上查相关内容)
    CMake实践(2)
    CMake实践(1)
    Centos6.5下编译安装ACE6.0
    回调函数的应用误区4(c/s OK版本回调小程序)
    回调函数的应用误区3(大彻大悟的回调小程序,例子的解释相当给力)
    回调函数的应用误区2(与原理相悖的回调函数)
    回调函数的应用误区1(原汁原味的函数指针应用)
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/7896160.html
Copyright © 2011-2022 走看看