https://www.codechef.com/problems/DGCD
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).
Input
First 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.
Example
Input:
6
0 4
0 5
1 5
5 2
3 5
3 1 3 2 4 2
5
F 3 5
C 1 3 1
C 3 4 4
F 3 0
F 2 5
Output:
2
7
1
Constraints
1 <= N <= 50000
1 <= Q <= 50000
0 <= u, v <= N-1
1 <= vi <= 10^4
0 <= d <= 10^4
思路:线段树维护gcd还是比较套路的,建议不会的先看一下这道题解。线段树的会了,其实树上的就也会了。毕竟树剖还是很模板的。注意gcd前先取个绝对值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=5e4+5;
struct node
{
int l,r,v;
}tree[maxn<<2];
struct edge
{
int to,nxt;
}Edge[maxn<<1];
int n,m,cnt=0,tot=0;
int head[maxn];
int dis[maxn];
int bit[maxn];
int siz[maxn],son[maxn],deep[maxn],fa[maxn],pos[maxn],top[maxn],a[maxn],v[maxn];
void dfs1(int u,int f)
{
fa[u]=f;
deep[u]=deep[f]+1;
siz[u]=1,son[u]=0;
for(int i=head[u];i;i=Edge[i].nxt)
{
if(Edge[i].to!=f)
{
dfs1(Edge[i].to,u);
siz[u]+=siz[Edge[i].to];
if(siz[Edge[i].to]>siz[son[u]])
son[u]=Edge[i].to;
}
}
}
void dfs2(int u,int f,int k)
{
top[u]=k;
pos[u]=++tot,v[tot]=a[u];
if(son[u])
dfs2(son[u],u,k);
for(int i=head[u];i;i=Edge[i].nxt)
if(Edge[i].to!=f&&Edge[i].to!=son[u])
dfs2(Edge[i].to,u,Edge[i].to);
}
inline void addedge(int u,int v)
{
Edge[++cnt].to=v,Edge[cnt].nxt=head[u],head[u]=cnt;
Edge[++cnt].to=u,Edge[cnt].nxt=head[v],head[v]=cnt;
}
inline int lowbit(int x)
{
return x&(-x);
}
inline void add(int pos,int v)
{
for(int i=pos;i<=n;i+=lowbit(i))
bit[i]+=v;
}
inline int sum(int pos)
{
int ans=0;
for(int i=pos;i;i-=lowbit(i))
ans+=bit[i];
return ans;
}
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
inline void up(int i)
{
tree[i].v=gcd(tree[i<<1].v,tree[i<<1|1].v);
}
void build(int i,int l,int r)
{
tree[i].l=l,tree[i].r=r;
if(l==r)
{
tree[i].v=v[l];
return;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
up(i);
}
void update(int i,int pos,int v)
{
if(tree[i].l==tree[i].r)
{
tree[i].v+=v;
return;
}
int mid=(tree[i].l+tree[i].r)>>1;
if(pos<=mid)
update(i<<1,pos,v);
else
update(i<<1|1,pos,v);
up(i);
}
int query(int i,int l,int r)
{
if(tree[i].l==l&&tree[i].r==r)
return tree[i].v;
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid)
return query(i<<1,l,r);
else if(l>mid)
return query(i<<1|1,l,r);
else
return gcd(query(i<<1,l,mid),query(i<<1|1,mid+1,r));
}
inline void updatework(int u,int v,int val)
{
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]])
swap(u,v);
add(pos[top[u]],val);
add(pos[u]+1,-val);
update(1,pos[top[u]],val);
if(pos[u]+1<=n)
update(1,pos[u]+1,-val);
u=fa[top[u]];
}
if(deep[u]>deep[v])
swap(u,v);
add(pos[u],val);
add(pos[v]+1,-val);
update(1,pos[u],val);
if(pos[v]+1<=n)
update(1,pos[v]+1,-val);
}
inline int querywork(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]])
swap(u,v);
ans=gcd(abs(ans),abs(sum(pos[top[u]])));
if(pos[top[u]]+1<=pos[u])
ans=gcd(abs(ans),abs(query(1,pos[top[u]]+1,pos[u])));
u=fa[top[u]];
}
if(deep[u]>deep[v])
swap(u,v);
ans=gcd(abs(ans),abs(sum(pos[u])));
if(pos[u]+1<=pos[v])
ans=gcd(abs(ans),abs(query(1,pos[u]+1,pos[v])));
return ans;
}
inline void prework()
{
scanf("%d",&n);
int u,vv;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&vv);
++u,++vv;
addedge(u,vv);
}
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs1(1,0);
dfs2(1,0,1);
for(int i=1;i<=n;i++)
add(i,v[i]),add(i+1,-v[i]);
for(int i=n;i>=1;i--)
v[i]-=v[i-1];
build(1,1,n);
}
inline void mainwork()
{
scanf("%d",&m);
char op[10];
int l,r;
ll d;
for(int i=0;i<m;i++)
{
scanf("%s%d%d",op,&l,&r);
++l,++r;
if(op[0]=='C')
{
scanf("%d",&d);
updatework(l,r,d);
}
else
printf("%d\n",querywork(l,r));
}
}
int main()
{
prework();
mainwork();
return 0;
}