• POJ 3728 The merchant(并查集+DFS)


    【题目链接】 http://poj.org/problem?id=3728

    【题目大意】

      给出一棵树,每个点上都可以交易货物,现在给出某货物在不同点的价格,
      问从u到v的路程中,只允许做一次买入和一次卖出,最多能得到多少钱。

    【题解】

      我们维护一个up表示,x与父节点的连线中,
      最大值在靠近父节点的位置时最小值与最大值的最大差值
      dw表示,x与父节点的连线中,最小值在靠近父节点的位置时最小值与最大值的最大差值
      Min和Max分别表示x到父节点中的最大值和最小值
      对于询问x到y的答案,我们发现以LCA为父节点时,答案只会是dwx,upy,和Maxx-Miny中的最优值,
      所以我们在每个查询的LCA位置计算答案,自低向上维护四个数组,
      这个用并查集就可以顺利完成了。

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cstring>
    using namespace std;
    const int N=50010;
    int n,m,f[N],ans[N],vis[N],Max[N],Min[N],up[N],dw[N],val[N];
    struct edge{int x,id;};
    struct data{int x,y;}p[N];
    vector<edge> Q[N];
    vector<int> G[N],a[N];
    int sf(int x){
        if(f[x]==x)return x;
        int fx=f[x];
        f[x]=sf(f[x]);
        up[x]=max(max(up[x],up[fx]),Max[fx]-Min[x]);
        dw[x]=max(max(dw[x],dw[fx]),Max[x]-Min[fx]);
        Max[x]=max(Max[x],Max[fx]);
        Min[x]=min(Min[x],Min[fx]);
        return f[x];
    }
    void dfs(int u){
        vis[u]=1;
        Max[u]=Min[u]=val[u];
        up[u]=dw[u]=0;
        for(int i=0;i<Q[u].size();i++){
            edge e=Q[u][i];
            if(vis[e.x])a[sf(e.x)].push_back(e.id);
        }
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!vis[v]){dfs(v);f[v]=u;}
        }
        for(int i=0;i<a[u].size();i++){
            int id=a[u][i];
            int x=p[id].x,y=p[id].y;
            sf(x); sf(y);
            ans[id]=max(max(up[x],dw[y]),Max[y]-Min[x]);
            ans[id]=max(0,ans[id]);
        }
    }
    void solve(){
        for(int i=1;i<=n;i++)scanf("%d",&val[i]);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }for(int i=1;i<=n;i++)f[i]=i;
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            Q[u].push_back(edge{v,i});
            Q[v].push_back(edge{u,i});
            p[i].x=u;p[i].y=v;
        }memset(vis,0,sizeof(vis));
        dfs(1);
        for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
    }
    int main(){
        while(~scanf("%d",&n))solve();
        return 0;
    }
  • 相关阅读:
    【重要】ASCII码表
    深入了解php opcode缓存原理
    php 请求参数限制
    【Demo】 生成二维码 和 条形码
    【Demo】HTML5 拍照上传
    jq cookie的使用
    vue.js中的v-for输出数组理解
    js无限轮播的写法
    HTML5视频的使用总结
    angular报错总计
  • 原文地址:https://www.cnblogs.com/forever97/p/poj3728.html
Copyright © 2020-2023  润新知