You’re given a tree on N vertices. Each vertex has a positive integer
written on it, number on the ith vertex being vi. Your program must
process two types of queries :
Find query represented by F u v : Find out gcd of all numbers on the unique path between vertices u and v in the tree (both inclusive).
Change query represented by C u v d : Add d to the number written on all vertices along the unique path between vertices u and v in the
tree (both inclusive). InputFirst line of input contains an integer N denoting the size of the
vertex set of the tree. Then follow N - 1 lines, ith of which contains
two integers ai and bi denoting an edge between vertices ai and bi in
the tree. After this follow N space separated integers in a single
line denoting initial values vi at each of these nodes. Then follows a
single integer Q on a line by itself, denoting the number of queries
to follow. Then follow Q queries, each one on a line by itself. Each
query is either a find query or a change query with format as given in
problem statement. Note that all vertices are 0-based. Output For
every find query, print the answer to that query in one line by
itself.
很明显用树剖,关键是线段树上如何维护GCD。
直接维护的话无法进行区间修改区间查询,但是考虑到辗转相减和差分,可以维护两个线段树,一个保存原序列【不妨看成原树的点】的值,进行区间修改单点查询,另一个保存差分序列【不妨看成原树的边】的GCD,进行单点修改区间查询。询问区间就是差分序列的GCD和原序列某一个数【为了方便取首或尾】的GCD,修改就是在差分序列上单点修改,原序列上打标记。
一个需要注意的细节就是在差分序列上单点修改的时候,改变一个端点的值会让他所有连边的值发生改变,如果全都修改的话复杂度就无法保证。所以我们只维护重边上的差分值,询问的时候用单点查询来代替轻边查询。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int fir[50010],ne[100010],to[100010],v[50010],
size[50010],fa[50010],son[50010],dep[50010],
pos[50010],top[50010],
tag[500010],val1[500010],gcd2[500010],
m,n,tot;
int abs(int x)
{
return x>0?x:-x;
}
int gcd(int x,int y)
{
return y?gcd(y,x%y):abs(x);
}
void add(int num,int u,int v)
{
ne[num]=fir[u];
fir[u]=num;
to[num]=v;
}
void init()
{
int i,x,y;
scanf("%d",&n);
for (i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
x++;
y++;
add(i*2,x,y);
add(i*2+1,y,x);
}
for (i=1;i<=n;i++)
scanf("%d",&v[i]);
}
void dfs1(int u)
{
int i,v;
size[u]=1;
for (i=fir[u];i;i=ne[i])
if ((v=to[i])!=fa[u])
{
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
size[u]+=size[v];
if (son[u]==0||size[v]>size[son[u]])
son[u]=v;
}
}
void dfs2(int u)
{
int i,v;
pos[u]=++tot;
if (!son[u]) return;
top[son[u]]=top[u];
dfs2(son[u]);
for (i=fir[u];i;i=ne[i])
if ((v=to[i])!=fa[u]&&v!=son[u])
{
top[v]=v;
dfs2(v);
}
}
void down1(int p,bool is)
{
if (is)
val1[p]+=tag[p];
else
{
tag[p*2]+=tag[p];
tag[p*2+1]+=tag[p];
}
tag[p]=0;
}
void m1(int p,int L,int R,int l,int r,int x)
{
down1(p,L==R);
int mid=(L+R)/2;
if (l<=L&&R<=r)
{
tag[p]=x;
return;
}
if (l<=mid) m1(p*2,L,mid,l,r,x);
if (r>=mid+1) m1(p*2+1,mid+1,R,l,r,x);
}
int q1(int p,int L,int R,int k)
{
down1(p,L==R);
if (L==R) return val1[p];
int mid=(L+R)/2;
if (k<=mid) return q1(p*2,L,mid,k);
return q1(p*2+1,mid+1,R,k);
}
void m2(int p,int L,int R,int k,int x)
{
if (L==R)
{
gcd2[p]+=x;
return;
}
int mid=(L+R)/2;
if (k<=mid) m2(p*2,L,mid,k,x);
else m2(p*2+1,mid+1,R,k,x);
gcd2[p]=gcd(gcd2[p*2],gcd2[p*2+1]);
}
int q2(int p,int L,int R,int l,int r)
{
if (l<=L&&R<=r) return gcd2[p];
int ret=0,mid=(L+R)/2;
if (l<=mid) ret=gcd(ret,q2(p*2,L,mid,l,r));
if (r>=mid+1) ret=gcd(ret,q2(p*2+1,mid+1,R,l,r));
return ret;
}
void pre()
{
int i;
dep[1]=1;
dfs1(1);
top[1]=1;
dfs2(1);
for (i=1;i<=n;i++)
m1(1,1,tot,pos[i],pos[i],v[i]);
for (i=1;i<=n;i++)
if (son[i])
m2(1,1,tot,pos[son[i]],v[i]-v[son[i]]);
}
int query(int u,int v)
{
int f1,f2,ret=0;
while ((f1=top[u])!=(f2=top[v]))
{
if (dep[f1]<dep[f2])
{
swap(u,v);
swap(f1,f2);
}
if (f1!=u) ret=gcd(ret,q2(1,1,tot,pos[son[f1]],pos[u]));
ret=gcd(ret,q1(1,1,tot,pos[f1]));
u=fa[f1];
}
if (dep[u]<dep[v])
swap(u,v);
if (u!=v) ret=gcd(ret,q2(1,1,tot,pos[son[v]],pos[u]));
ret=gcd(ret,q1(1,1,tot,pos[v]));
return ret;
}
void modify(int u,int v,int x)
{
int f1,f2;
while ((f1=top[u])!=(f2=top[v]))
{
if (dep[f1]<dep[f2])
{
swap(u,v);
swap(f1,f2);
}
m1(1,1,tot,pos[f1],pos[u],x);
if (son[u]) m2(1,1,tot,pos[son[u]],x);
u=fa[f1];
}
if (dep[u]<dep[v])
swap(u,v);
m1(1,1,tot,pos[v],pos[u],x);
if (son[u]) m2(1,1,tot,pos[son[u]],x);
if (son[fa[v]]==v) m2(1,1,tot,pos[v],-x);
}
int main()
{
int x,y,z;
char s[5];
init();
pre();
scanf("%d",&m);
while (m--)
{
scanf("%s",s);
if (s[0]=='F')
{
scanf("%d%d",&x,&y);
x++;
y++;
printf("%d\n",query(x,y));
}
else
{
scanf("%d%d%d",&x,&y,&z);
x++;
y++;
modify(x,y,z);
}
}
}