题意
给一棵树,点有点权,有两种操作:询问路径点权gcd,将路径点权+val;
1 <= N <= 50000
1 <= Q <= 50000
0 <= u, v <= N-1
1 <= vi <= 104 //初始点权
0 <= d <= 104 //增加点权
题解
先树链剖分,就和序列的gcd求法差不多,记得询问取abs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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 ",query(x,y)); else { int val; read(val); modify(x,y,val); } } }