poj 3728(LCA+并查集+DP)

88 篇文章 0 订阅
           思路理解,但是代码实现不行,其中是并查集更新他复杂了,,,另外,可以用RMQ来搞。代码是修改别人的代码的。
           转:
           题意:给出一棵节点有值的树,给出Q个询问(a,b),问从a到b的最大盈利(即:先在最小值买入,再在最大值卖出)
          分析:这题其实就是在一棵树上找RMQ,于是很多人都转化为rmq问题来做,尽管都说非常好做,但是由于本菜对RMQ实在不熟悉,花了整整一个下午半个晚上来想rmq的转移。。。无果,后来看到一篇博客印证了一开始我的想法是对的,只要在求LCA时,并查集合并的时候更新一些数据即可
假设 询问Q(x,y)LCA(x,y)=z
即记录 max(x) x到z路径上的最大值
             min(x) x到z路径上的最小值
             up(x) x到z的最优解
             down(x) z到x的最优解
于是答案=MAX(max(y)-min(x),up(x),down(y));
对应的:
最小价格 (从祖先走到自己的最大价格)max
最大价格  (从祖先走到自己的最小价格)min
最大收益(从自己走到祖先)metomax
最大收益(从祖先走到自己)tomemax

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>


using namespace std;
#define nNode 50005


int Max (int a,int b)
{
    return a>b?a:b;
}


int Min (int a,int b)
{
    return a<b?a:b;
}

struct Node
{
    int father,minn,maxx,tomemax,metomax;
}Set[nNode];


struct Query
{
    int v,id,opp;//opp 表示 s->v or v->s
    Query(int a,int b,int c)
    {v=a;id=b;opp=c;};
};
vector <int> tree[nNode];
vector <Query> Q[nNode];

bool color[nNode];
int value[nNode];
int ans[nNode];
int pre[nNode];
void Init(int n)
{
    int i;
    for(i=0;i<=n;i++)
    {
        tree[i].clear();
        Q[i].clear();
        color[i]=false;
        Set[i].father=i;
        Set[i].maxx=value[i];//一开始每个点在一个集合里 所以max,min =自己价格;
        Set[i].metomax=0;
        Set[i].minn=value[i];
        Set[i].tomemax=0;
    }
}


int Find(int x)
{
    int px=Set[x].father;//其父节点
    if(x!=px)
    {
        Set[x].father=Find(px);
        Set[x].metomax=Max(Set[px].metomax,Max(Set[x].metomax,Set[px].maxx-Set[x].minn));//更新metomax
        Set[x].tomemax=Max(Set[px].tomemax,Max(Set[x].tomemax,Set[x].maxx-Set[px].minn));
        Set[x].maxx=Max(Set[x].maxx,Set[px].maxx);
        Set[x].minn=Min(Set[x].minn,Set[px].minn);
    }
    return Set[x].father;
}


void Union(int x, int y)
{
    Set[Find(x)].father = Set[Find(y)].father;
}


void LCA(int s)
{
    int i,sz,t;
    sz=tree[s].size();
    for(i=0;i<sz;i++)
    {
        t=tree[s][i];
        if(t!=pre[s])
        {
            pre[t]=s;
            LCA(t);
            Union(tree[s][i],s);
        }
    }
    color[s]=true;
    sz=Q[s].size();
    for(i=0;i<sz;i++)
    {
        if(color[Q[s][i].v])//注意这里只又算到了 从公共祖先到Q[s].v的信息,而s到公共祖先的信息却没有
        {
            t=Find(Q[s][i].v);
            int v,mi,ma,tomax;//下面是求s到公共祖先的信息
             mi=ma=value[s];
               tomax=0;
               v=s;
            if(Q[s][i].opp==0) //s->Q[s][i].v
            {
               while(v!=t)
               {
                     tomax=Max(Set[v].metomax,Max(tomax,Set[v].maxx-mi));
                     mi=Min(mi,Set[v].minn);
                     v=pre[v];
               }
               ans[Q[s][i].id]=Max(Max(tomax,Set[Q[s][i].v].tomemax),Set[Q[s][i].v].maxx-mi);
            }
            else
            {
                while(v!=t)
                {
                 tomax=Max(Set[v].tomemax,Max(tomax,ma-Set[v].minn));
                 ma=Max(ma,Set[v].maxx);
                 v=pre[v];
                }
                 ans[Q[s][i].id]=Max(Max(tomax,Set[Q[s][i].v].metomax),ma-Set[Q[s][i].v].minn);
            }
        }
    }
}


int main()
{
    int n,i,a,b;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++)
        scanf("%d",&value[i]);
         Init(n);
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            tree[a].push_back(b);
            tree[b].push_back(a);
        }
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            Q[a].push_back(Query(b,i,0));
            Q[b].push_back(Query(a,i,1));
        }
        LCA(1);
        for(i=0;i<n;i++)
        {
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值