给定一棵树
1:求链上gcd
2:给一个路径共同加一个给定数
待区间修改的区间gcd问题,可以用差分后线段树做。就是 gcd(起始位置原值,之后的差分数组中gcd);
对于树上,只需要把树剖成链,对于询问和操作,单独处理每一个小区间就好,做法和序列上一样。
区间修改就是,在差分数组中 head位置加上val,tail+1位置减去val
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=50005;
inline int read()
{
int ans,f=1;char ch;
while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0';
while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';
return ans*f;
}
int n,m;
int val[N];
int head[N],to[N*2],pre[N*2],tot;
void addedge(int u,int v)
{
to[++tot]=v;pre[tot]=head[u];head[u]=tot;
}
int dep[N],size[N],son[N],id[N],cnt,top[N],fa[N],v[N];
void dfs1(int u,int fat,int depth)
{
dep[u]=depth;
size[u]=1;
fa[u]=fat;
int mx=0;
for (int i=head[u];i;i=pre[i]) if (to[i]!=fat)
{
dfs1(to[i],u,depth+1);
if (size[to[i]]>mx) mx=size[to[i]],son[u]=to[i];
size[u]+=size[to[i]];
}
}
void dfs2(int u,int anc)
{
id[u]=++cnt;
top[u]=anc;v[cnt]=val[u];
if (son[u]) dfs2(son[u],anc);
for (int i=head[u];i;i=pre[i])
if (to[i]!=son[u]&&to[i]!=fa[u]) dfs2(to[i],to[i]);
}
struct aa
{
int l,r;
int d,add;
}a[N*4];
int gcd(int a,int b){return b==0 ? a:gcd(b,a%b);}
void up(int i)
{
a[i].d=gcd(a[i<<1].d,a[i<<1|1].d);
}
void build(int i,int l,int r)
{
a[i].l=l,a[i].r=r;
if (l==r)
{
a[i].d=v[l]-v[l-1];
a[i].add=v[l];
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
up(i);
}
int get(int i,int pos)
{
if (a[i].l==a[i].r) return a[i].add;
int mid=(a[i].l+a[i].r)>>1;
if (pos<=mid) return a[i].add+get(i<<1,pos);
return a[i].add+get(i<<1|1,pos);
}
int find_gcd(int i,int l,int r)
{
if (l>r) return 0;
if (a[i].l==l&&a[i].r==r) return a[i].d;
int mid=(a[i].l+a[i].r)>>1;
if (r<=mid) return find_gcd(i<<1,l,r);
else if (mid<l) return find_gcd(i<<1|1,l,r);
return gcd(find_gcd(i<<1,l,mid),find_gcd(i<<1|1,mid+1,r));
}
void find(int x,int y)
{
int ans=0;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
ans=gcd(ans,get(1,id[top[x]]));
ans=gcd(ans,find_gcd(1,id[top[x]]+1,id[x]));
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
ans=gcd(ans,get(1,id[x]));
ans=gcd(ans,find_gcd(1,id[x]+1,id[y]));
printf("%d\n",abs(ans));
}
void add(int i,int l,int r,int d)
{
if (a[i].l==l&&a[i].r==r)
{
a[i].add+=d;
return ;
}
int mid=(a[i].l+a[i].r)>>1;
if (r<=mid) add(i<<1,l,r,d);
else if (l>mid) add(i<<1|1,l,r,d);
else add(i<<1,l,mid,d),add(i<<1|1,mid+1,r,d);
}
void add_gcd(int i,int pos,int d)
{
if (a[i].l==a[i].r)
{
a[i].d+=d;
return ;
}
int mid=(a[i].l+a[i].r)>>1;
if (pos<=mid) add_gcd(i<<1,pos,d);
else add_gcd(i<<1|1,pos,d);
up(i);
}
void add(int x,int y,int d)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
add(1,id[top[x]],id[x],d);
add_gcd(1,id[top[x]],d);
add_gcd(1,id[x]+1,-d);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
add(1,id[x],id[y],d);
add_gcd(1,id[x],d);
add_gcd(1,id[y]+1,-d);
}
int main()
{
n=read();
int q,x,y,t;
char ch[2];
for (int i=1;i<n;i++)
{
x=read()+1,y=read()+1;
addedge(x,y);
addedge(y,x);
}
for (int i=1;i<=n;i++) val[i]=read();
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
m=read();
for (int i=1;i<=m;i++)
{
scanf("%s",ch);
x=read()+1,y=read()+1;
if (ch[0]=='F') find(x,y);else {t=read();
add(x,y,t);}
}
return 0;
}