zoukankan      html  css  js  c++  java
  • poj 3728 The merchant

    LCA

    参考Yuan神博客:

    /*
        题意:给出一棵节点有值的树,给出Q个询问(a,b),问从a到b的最大盈利(即:先在最小值买入,再在最大值卖出)
        我有想过用一个新序列w2-w1 , w3-w2 ,  , wn-wn-1
        这样只需用O(n)求得最大子段和即为结果Max-Min了
        但Q很大,每次都找一个路径会超时
        用类似Tarjan算法进行处理,但在find()那里要修改一下
        对每个几点记录4个值
        up[v] 表示从v到目前的根的最大盈利
        down[v] 从目前的根到v的最大盈利
        Max[v]表示到目前的根的最大值
        Min[v]表示到目前的根的最小值
        转移看update!    
        在LCA(u,v)处再来计算,这样那四个值才是正确的值!!
    */

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define N 50010
    #define Q 50010
    #define M 50010
    #define INF 0x3f3f3f3f
    
    int val[N],tote,totea,totes;
    int head[N];
    struct edge{
        int u,v,next;
    }e[5*M];
    int __head[N];
    struct ask{
        int u,v,lca,next;
    }ea[5*Q];
    int head__[N];
    struct res{
        int n,next;
    }es[5*Q];
    bool vis[N];
    int up[N],down[N],Max[N],Min[N],ans[Q],fa[N];
    
    inline void add_edge(int u ,int v){
        e[tote].u = u; e[tote].v = v; 
        e[tote].next = head[u]; head[u] = tote++;
    }
    inline void add_ask(int u ,int v){
        ea[totea].u = u; ea[totea].v = v; ea[totea].lca = -1;
        ea[totea].next = __head[u]; __head[u] = totea++;
    }
    inline void add_ans(int u ,int k){
        es[totes].n = k; es[totes].next = head__[u]; head__[u] = totes++;
    }
    
    int updata(int v)
    {
        if(v == fa[v]) return v;
        int par = fa[v];
        fa[v] = updata(fa[v]);
        up[v] = max( up[v] , max(up[par] , Max[par]-Min[v]) );
        down[v] = max( down[v] , max(down[par] , Max[v] - Min[par]));
        Max[v] = max(Max[v] , Max[par]);
        Min[v] = min(Min[v] , Min[par]);
        return fa[v];
    }
    
    void Tarjan(int u)
    {
        for(int k=__head[u]; k!=-1; k=ea[k].next)
            if(vis[ea[k].v])
            {
                int v = ea[k].v;
                int lca = updata(v);
                add_ans(lca,k);
            }
        vis[u] = true; fa[u] = u;
        for(int k=head[u]; k!=-1; k=e[k].next)
            if(!vis[e[k].v])
            {
                int v = e[k].v;
                Tarjan(v);
                fa[v] = u;
            }
    
        for(int i=head__[u]; i!=-1; i=es[i].next)
        {
            int k = es[i].n , x = ea[k].u , y = ea[k].v;
            if(k&1) //
            { k = k^1; swap(x,y); }
            k /= 2;
            updata(x); updata(y);
            ans[k] = max(up[x] , down[y]);
            ans[k] = max(ans[k] , Max[y] - Min[x]);
        }
            
    }
    
    int main()
    {
        int n,q;
        while(scanf("%d",&n)!=EOF)
        {
            tote = totea = totes = 0;
            memset(head,-1,sizeof(head));
            memset(__head,-1,sizeof(__head));
            memset(head__,-1,sizeof(head__));
            memset(vis,false,sizeof(vis));
            memset(ans,0,sizeof(ans));
    
            for(int i=1; i<=n; i++){
                scanf("%d",&val[i]); 
                up[i] = down[i] = 0;
                Max[i] = Min[i] = val[i];
            }
    
            for(int i=1; i<n; i++){
                int u,v;
                scanf("%d%d",&u,&v);
                add_edge(u,v);
                add_edge(v,u);
            }
    
            scanf("%d",&q);
            for(int i=0; i<q; i++){
                int u,v;
                scanf("%d%d",&u,&v);
                add_ask(u,v);
                add_ask(v,u);
            }
    
            Tarjan(1);
            for(int i=0; i<q; i++) printf("%d\n",ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    顺流交易中,母公司销售部分存货,为什么收入也是全额抵消?
    借:递延所得税资产(负债)贷:所得税费用
    可变回报与固定回报
    或有对价
    可以税前扣除什么意思
    应收账款保理为什么是筹资活动
    外币报表折算差额计入其他综合收益
    分配现金股利为什么是筹资
    spring的@EnableAspectJAutoproxy注解
    Spring的@DeclareParents注解
  • 原文地址:https://www.cnblogs.com/scau20110726/p/3110663.html
Copyright © 2011-2022 走看看