Codechef DGCD Dynamic GCD(D12 树上GCD)

题意

给一棵树,点有点权,有两种操作:询问路径点权gcd,将路径点权+val;

1 <= N <= 50000
1 <= Q <= 50000
0 <= u, v <= N-1 
1 <= vi <= 104 //初始点权
0 <= d <= 104 //增加点权

题解

先树链剖分,就和序列的gcd求法差不多,记得询问取abs

#include<bits/stdc++.h>
using namespace std;

const int maxn=50005;
int n,m;
int a[maxn],aa[maxn];
int head[maxn],cnt;
int size[maxn],fa[maxn],dep[maxn],son[maxn];
int top[maxn],id[maxn];
int root,ls[maxn<<1],rs[maxn<<1],gcd[maxn<<1];
int cx[maxn];
struct edge{
    int y,next;
}e[maxn<<1];

template<class T>inline void read(T &x){
    x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
} 

void addedge(int x,int y){
    e[++cnt]=(edge){y,head[x]};
    head[x]=cnt;
}

void dfs(int u){
    size[u]=1;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].y;
        if(v==fa[u]) continue;
        fa[v]=u;
        dep[v]=dep[u]+1;
        dfs(v);
        size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
}

void dfs(int u,int tp){
    id[u]=++cnt;
    aa[cnt]=a[u];
    top[u]=tp;
    if(!son[u]) return ;
    dfs(son[u],tp);
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].y;
        if(v==fa[u]||v==son[u]) continue;
        dfs(v,v);
    }
}

void add(int x,int val){for(;x<=n;x+=x&-x) cx[x]+=val;}
int sum(int x){
    int ret=0;
    for(;x;x-=x&-x)
     ret+=cx[x];
    return ret;
}

int get_gcd(int a,int b){
    return !b ? a : get_gcd(b,a%b);
}

void update(int rt){
    gcd[rt]=get_gcd(gcd[ls[rt]],gcd[rs[rt]]);
}

void build(int &rt,int l,int r){
    rt=++cnt;
    if(l==r) {gcd[rt]=aa[l];return ;}
    int mid=(l+r)>>1;
    build(ls[rt],l,mid);
    build(rs[rt],mid+1,r);
    update(rt);
}

int query(int rt,int l,int r,int a_l,int a_r){
    if(a_r<a_l) return 0;
    if(a_l<=l&&r<=a_r) return gcd[rt];
    int mid=(l+r)>>1;
    if(a_r<=mid) return query(ls[rt],l,mid,a_l,a_r);
    if(mid<a_l) return query(rs[rt],mid+1,r,a_l,a_r);
    return get_gcd(query(ls[rt],l,mid,a_l,a_r),query(rs[rt],mid+1,r,a_l,a_r));
}

int query(int x,int y){
    int ans=0,ret;
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        ret=abs(get_gcd(sum(id[top[y]]),query(1,1,n,id[top[y]]+1,id[y])));
        ans=get_gcd(ret,ans);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ret=abs(get_gcd(sum(id[x]),query(1,1,n,id[x]+1,id[y])));
    return get_gcd(ans,ret);
}

void modify(int rt,int l,int r,int pos,int val){
    if(l==r){
        gcd[rt]+=val;
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) modify(ls[rt],l,mid,pos,val);
    else modify(rs[rt],mid+1,r,pos,val);
    update(rt);
}

void modify(int x,int y,int val){
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        add(id[top[y]],val);
        add(id[y]+1,-val);
        modify(1,1,n,id[top[y]],val);
        if(id[y]<n) modify(1,1,n,id[y]+1,-val);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    add(id[x],val);
    add(id[y]+1,-val);
    modify(1,1,n,id[x],val);
    if(id[y]<n) modify(1,1,n,id[y]+1,-val);
}

int main(){
    read(n);
    for(int i=1;i<n;i++){
        int x,y;
        read(x);read(y);
        x++;y++;
        addedge(x,y);addedge(y,x);
    }
    cnt=0;
    for(int i=1;i<=n;i++) read(a[i]);
    dep[1]=1;
    dfs(1);
    dfs(1,1);
    for(int i=n;i;i--) aa[i]-=aa[i-1],add(i,aa[i]);
    cnt=0;
    build(root,1,n);
    read(m);
    for(int i=1;i<=m;i++){
        char op[2];
        int x,y;
        scanf("%s",op);
        read(x);read(y);x++;y++;
        if(op[0]=='F') printf("%d\n",query(x,y));
        else {
            int val;
            read(val);
            modify(x,y,val);
        }
    }
}
View Code
posted @ 2019-07-24 21:17  _JSQ  阅读(256)  评论(0编辑  收藏  举报