POJ 3728 The merchant

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=34528#problem/L


#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 50010;
const int POW  = 17;
const int INF  = 0x3f3f3f3f;
int val[MAXN], head[MAXN], cnt;
int parent[MAXN][POW], dep[MAXN], mmin[MAXN][POW], mmax[MAXN][POW], up[MAXN][POW], down[MAXN][POW];

/*
*parent[i][j]: 表示距离顶点i为2^j的祖先顶点的编号
*up[i][j]: i->距离i为2^j的祖先顶点最大收益
*down[i][j]: 距离i为2^j的祖先顶点->i顶点的最小收益
*mmin[i][j]: i->距离i为2^j的祖先顶点的最小顶点的权值
*mmax[i][j]: i->距离i为2^j的祖先顶点的最大顶点的权值
*因此对于一组询问(u,v) ans = max(getmax_up(u, lca(u,v)), getmax_dwon(v, lca(u,v)), getmax(v, lca(u,v))-getmin(u, lca(u,v)))
*/

struct Edge
{
    int v, next;
    Edge() {}
    Edge(int t_v, int t_next) : v(t_v), next(t_next) {}
}edge[2*MAXN];

void addedge(int u, int v)
{
    edge[cnt].v = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;

    edge[cnt].v = u;
    edge[cnt].next = head[v];
    head[v] = cnt++;
}

void Init(int n)
{
    cnt = 0;
    memset(head, -1, sizeof(head));
    memset(dep,   0,   sizeof(dep));
    memset(parent, 0, sizeof(parent));
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 0; j < POW; ++j)
        {
            mmin[i][j] = mmax[i][j] = up[i][j] = down[i][j] = 0;
        }
    }
}

void dfs(int u, int fa)
{
    int i, j;
    dep[u] = dep[fa] + 1;
    for(i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].v;
        if(v == fa) continue;
        ////////////////////////////////////////////////////////////////////////////////
        parent[v][0] = u;
        mmin[v][0] = min(val[u], val[v]);
        mmax[v][0] = max(val[u], val[v]);
        up[v][0]   = val[u] - val[v];
        down[v][0] = val[v] - val[u];
        for(j = 1; (1<<j) <= dep[u] + 1; j++)
        {
            parent[v][j] = parent[parent[v][j-1]][j-1];
            mmin[v][j]   = min(mmin[v][j-1], mmin[parent[v][j-1]][j-1]);
            mmax[v][j]   = max(mmax[v][j-1], mmax[parent[v][j-1]][j-1]);

            up[v][j] = max(up[v][j-1], up[parent[v][j-1]][j-1]);
            up[v][j] = max(up[v][j],   mmax[parent[v][j-1]][j-1] - mmin[v][j-1]);

            down[v][j] = max(down[v][j-1], down[parent[v][j-1]][j-1]);
            down[v][j] = max(down[v][j],   mmax[v][j-1] - mmin[parent[v][j-1]][j-1]);
        }
        /////////////////////////////////////////////////////////////////////////////////
        dfs(v, u);
    }
    return ;
}

int LCA(int u, int v)
{
    int i;
    if(dep[u] > dep[v]) u ^= v, v ^= u, u ^= v;

    if(dep[u] < dep[v])
    {
        int del = dep[v] - dep[u];
        for(i = 0; i < POW; i++)
            if(del & (1<<i))
                v = parent[v][i];
    }
    if(u != v)
    {
        for(i = POW - 1; i >= 0; i--)
            if(parent[u][i] != parent[v][i])
                u = parent[u][i], v = parent[v][i];
        u = parent[u][0], v = parent[v][0];
    }
    return u;
}

int getmax_up(int u, int v)
{
    int ans = 0, i, tmp = INF;
    int del = dep[u] - dep[v];
    for(i = POW-1; i >= 0; i--)
    {
        if(del & (1<<i))
        {
            ans = max(ans, up[u][i]);
            ans = max(ans, mmax[u][i] - tmp);
            tmp = min(tmp, mmin[u][i]);
            u   = parent[u][i];
        }
    }
    return ans;
}

int getmax_down(int u, int v)
{
    int ans = 0, i, tmp = 0;
    int del = dep[u] - dep[v];
    for(i = POW-1; i >= 0; i--)
    {
        if(del & (1<<i))
        {
            ans = max(ans, down[u][i]);
            ans = max(ans, tmp - mmin[u][i]);
            tmp = max(tmp, mmax[u][i]);
            u   = parent[u][i];
        }
    }
    return ans;
}

int getmax(int u, int v)
{
    int ans = 0, i;
    int del = dep[u] - dep[v];
    for(i = POW-1; i >= 0; i--)
    {
        if(del & (1<<i))
        {
            ans = max(ans, mmax[u][i]);
            u   = parent[u][i];
        }
    }
    return ans;
}

int getmin(int u, int v)
{
    int ans = INF, i;
    int del = dep[u] - dep[v];
    for(i = POW-1; i >= 0; i--)
    {
        if(del & (1<<i))
        {
            ans = min(ans, mmin[u][i]);
            u   = parent[u][i];
        }
    }
    return ans;
}

void solve(int u, int v)
{
    int lca = LCA(u, v);
    int a, b, c, d;
    a = getmax_up(u, lca);
    b = getmax_down(v, lca);
    c = getmin(u, lca);
    d = getmax(v, lca);
    printf("%d\n", max(max(a, b), d - c));
}

int main()
{
    //freopen("aa.in", "r", stdin);

    int i, u, v, n, q;
    scanf("%d", &n);
    Init(n);
    for(i = 1; i <= n; i++)
        scanf("%d", &val[i]);
    for(i = 1; i < n; i++)
    {
        scanf("%d %d", &u, &v);
        addedge(u, v);
    }
    dfs(1, 0);
    scanf("%d", &q);
    for(i = 1; i <= q; i++)
    {
        scanf("%d %d", &u, &v);
        solve(u, v);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值