CodeChef 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 gcdof 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 Ndenoting 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
大致题意:给一棵树,每个点都有点权.现在有两种操作:1.将u到v的路径上的点的点权都加k. 2.求u到v的路径上的点的gcd.
分析:两个点之间的路径,很容易想到树链剖分.常见的套路用线段树维护,但是这样的话就不好处理区间加了.需要用到gcd的一个性质:
gcd(a,b,c,d......) = gcd(a,b-c,c-d,......).也就是说只需要知道首元素的值和差分后序列的gcd就可以了.因为差分过了,所以修改操作可以直接变成单点修改.在pushup的时候就能更新gcd.这样的话会有一个问题.差分修改一个区间的后继,在树上,一个点可能有多个子节点,那么它的后继是谁呢?很容易就能想到是重儿子,因为我们查询和修改每次都是从重链往上跳,用到的自然就是重儿子的值.那么整体的思路就是用线段树维护差分+区间修改+单点查询.
说起来挺容易的,其实写起来比较复杂.首先差分有可能将数变成负的,gcd求出来就可能是一个负数,解决方法就是在最后输出答案的时候加一个abs. 第二个就是这道题建树的时候因为是要建差分序列,所以要在第二次dfs的时候处理出每个id对应的值(见代码),再一个就是查询的时候可能会遇到空区间,要及时特判掉. 最坑的就是线段树的标记下传会T掉!这道题卡时卡的丧心病狂,正确的做法是将一路的标记直接加上,不下传.最好使用快读.
调了一天QAQ,不过最后终于卡着时过了.
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 50010;

int n,q,head[maxn],to[maxn * 2],nextt[maxn * 2],tot = 1,v[maxn];
int dep[maxn],sizee[maxn],top[maxn],cnt,son[maxn],id[maxn],idx[maxn],fa[maxn];
int c[maxn << 2],tag[maxn << 2],g[maxn << 2],val[maxn];

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 gcd(int a,int b)
{
    if (!b)
        return a;
    return gcd(b,a % b);
}

void add(int x,int y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void dfs(int u,int d,int from)
{
    dep[u] = d;
    sizee[u] = 1;
    fa[u] = from;
    for (int i = head[u];i;i = nextt[i])
    {
        int v = to[i];
        if (v == from)
            continue;
        dfs(v,d + 1,u);
        sizee[u] += sizee[v];
        if (sizee[v] >= sizee[son[u]])
            son[u] = v;
    }
}

void dfs2(int u,int topp)
{
    top[u] = topp;
    id[u] = ++cnt;
    val[cnt] = v[u];
    if (son[u])
        dfs2(son[u],topp);
    for (int i = head[u];i;i = nextt[i])
    {
        int v = to[i];
        if (v == son[u] || v == fa[u])
            continue;
        dfs2(v,v);
    }
}

void pushup(int o)
{
    g[o] = gcd(g[o * 2],g[o * 2 + 1]);
}

void build(int o,int l,int r)
{
    if (l == r)
    {
        c[o] = val[l];
        g[o] = val[l] - val[l - 1];
        return;
    }
    int mid = (l + r) >>1;
    build(o * 2,l,mid);
    build(o * 2 + 1,mid + 1,r);
    pushup(o);
}

void update1(int o,int l,int r,int x,int y,int v) //权值区间修改
{
    if (x <= l && r <= y)
    {
        c[o] += v;
        return;
    }
    int mid = (l + r) >> 1;
    if (x <= mid)
        update1(o * 2,l,mid,x,y,v);
    if (y > mid)
        update1(o * 2 + 1,mid + 1,r,x,y,v);
}

void update2(int o,int l,int r,int cur,int v) //gcd单点修改
{
    if (l == r)
    {
        g[o] += v;
        return;
    }
    pushdown(o);
    int mid = (l + r) >> 1;
    if (cur <= mid)
        update2(o * 2,l,mid,cur,v);
    if (cur > mid)
        update2(o * 2 + 1,mid + 1,r,cur,v);
    pushup(o);
}

int query1(int o,int l,int r,int cur) //单点询问权值
{
    if (l == r)
        return c[o];
    pushdown(o);
    int mid = (l + r) >> 1;
    if (cur <= mid)
        return c[o] + query1(o * 2,l,mid,cur);
    if (cur > mid)
        return c[o] + query1(o * 2 + 1,mid + 1,r,cur);
}

int query2(int o,int l,int r,int x,int y)  //询问区间gcd
{
    if (x > y)
        return 0;
    if (x <= l && r <= y)
        return g[o];
    pushdown(o);
    int mid = (l + r) >> 1,res = 0;
    if (x <= mid)
    {
        int t = query2(o * 2,l,mid,x,y);
        if (!res)
            res = t;
    }
    if (y > mid)
    {
        int t = query2(o *2 + 1,mid + 1,r,x,y);
        if (!res)
            res = t;
        else
            res = gcd(res,t);
    }
    return res;

}

int solve1(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,query1(1,1,n,id[top[x]]));
        ans = gcd(ans,query2(1,1,n,id[top[x]] + 1,id[x]));
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        swap(x,y);
    ans = gcd(ans,query1(1,1,n,id[x]));
    ans = gcd(ans,query2(1,1,n,id[x] + 1,id[y]));
    return abs(ans);
}

void solve2(int x,int y,int d)
{
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            swap(x,y);
        update1(1,1,n,id[top[x]],id[x],d);
        update2(1,1,n,id[top[x]],d);
        update2(1,1,n,id[x] + 1,-d);
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        swap(x,y);
    update1(1,1,n,id[x],id[y],d);
    update2(1,1,n,id[x],d);
    update2(1,1,n,id[y] + 1,-d);
}

int main()
{
    n = read();
    for (int i = 1; i < n; i++)
    {
        int u,v;
        u = read(),v = read();
        u++;
        v++;
        add(u,v);
        add(v,u);
    }
    for (int i = 1; i <= n; i++)
        v[i] = read();
    dfs(1,1,0);
    dfs2(1,1);
    build(1,1,n);
    q = read();
    while (q--)
    {
        char s[2];
        int a,b,c;
        scanf("%s",s);
        if (s[0] == 'F')
        {
            a = read();
            b = read();
            a++;
            b++;
            printf("%d\n",solve1(a,b));
        }
        else
        {
            a = read();
            b = read();
            c = read();
            a++;
            b++;
            solve2(a,b,c);
        }
    }

    return 0;
}

 

 
posted @ 2017-12-23 23:50  zbtrs  阅读(328)  评论(0编辑  收藏  举报