CodeChef DGCD Dynamic GCD 树链剖分+线段树维护gcd

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 :

  1. 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).

  2. 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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值