zoukankan      html  css  js  c++  java
  • poj3728 The merchant

    Time Limit: 3000MS   Memory Limit: 65536K
    Total Submissions: 3761   Accepted: 1268

    Description

    There are N cities in a country, and there is one and only one simple path between each pair of cities. A merchant has chosen some paths and wants to earn as much money as possible in each path. When he move along a path, he can choose one city to buy some goods and sell them in a city after it. The goods in all cities are the same but the prices are different. Now your task is to calculate the maximum possible profit on each path.

    Input

    The first line contains N, the number of cities.
    Each of the next N lines contains wi the goods' price in each city.
    Each of the next N-1 lines contains labels of two cities, describing a road between the two cities.
    The next line contains Q, the number of paths.
    Each of the next Q lines contains labels of two cities, describing a path. The cities are numbered from 1 to N.

    1 ≤ NwiQ ≤ 50000 

    Output

    The output contains Q lines, each contains the maximum profit of the corresponding path. If no positive profit can be earned, output 0 instead.

    Sample Input

    4
    1 
    5 
    3 
    2
    1 3
    3 2
    3 4
    9
    1 2
    1 3
    1 4
    2 3
    2 1
    2 4
    3 1
    3 2
    3 4

    Sample Output

    4
    2
    2
    0
    0
    0
    0
    2
    0


         这题花了很长时间啊..想明白后发现对离线tarjan算法的理解更深了,tarjan的算法核心是先处理较深的子树,然后再处理较浅的子树。这道题也是一样,因为样例很多,所以普通的暴力方法不行,这里就要结合taijan的特点,先把询问的问题分类,然后遍历到某个节点,就把最近公共祖先为这个节点的所有问题都处理完,然后再求这个节点父节点的问题。

        因为获得价值最大只有三种情况,设f为u,v的最近公共祖先,一种是起点u到f的最大区间值,一种是f到终点v的最大区间值,还有就是f到v经过的最大值减去u到f经过的最小值。所以要记录4个变量:

    up[u]表示u->f的最大maxval  
    down[u]表示f->u的最大maxval  
    maxw[u]表示u-f的最大w[i]  
    minw[u]表示u-f的最小w[i]  

    然后在并查集压缩路径的时候更新。


    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<string>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    #define inf 0x7fffffff
    #define maxn 50050
    int first[maxn],pre[maxn],vis[maxn],w[maxn],uu[maxn],vv[maxn];
    struct node{
        int to,next;
    }e[2*maxn];
    
    int h[maxn];
    struct node1{
        int to,next,idx;
    }question[2*maxn];
    
    int h1[maxn];
    struct node2{
        int next,idx;
    }question1[2*maxn];
    
    int answer[2*maxn];
    int maxw[maxn],minw[maxn],up[maxn],down[maxn];
    int tot;
    
    int findx(int x){  //这里要用递归写法
        int i,j=x,r=x;
        if(pre[x]==x){
            return x;
        }
        int fa=pre[x];
        pre[x]=findx(fa);
        up[x]=max(max(up[fa],up[x]),maxw[fa]-minw[x]); //这里上面两个与下面两个位置不能换
        down[x]=max(max(down[fa],down[x]),maxw[x]-minw[fa]);
        minw[x]=min(minw[x],minw[fa]);
        maxw[x]=max(maxw[x],maxw[fa]);
        return pre[x];
    }
    void lca(int u){
        int i,j,x,y,v,idx;
        vis[u]=1;
        for(i=h[u];i!=-1;i=question[i].next){  //对问题进行分类,把祖先同为f的放在一起解决,这样递归上来的时候就会解决了
            v=question[i].to;
            idx=question[i].idx;
            if(!vis[v])continue;
            int f=findx(v);
            tot++;
            question1[tot].next=h1[f];question1[tot].idx=idx;
            h1[f]=tot;
        }
        for(i=first[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(vis[v])continue;
            lca(v);
            pre[v]=u;
            findx(v);
        }
        for(i=h1[u];i!=-1;i=question1[i].next){
            idx=question1[i].idx;
            findx(uu[idx]);
            findx(vv[idx]);
            int t=max(up[uu[idx] ],down[vv[idx] ]);
            answer[question1[i].idx ]=max(t,maxw[vv[idx] ]-minw[uu[idx] ]);
        }
    
    }
    
    
    int main()
    {
        int n,m,i,j,tot,q,c,d;
        while(scanf("%d",&n)!=EOF)
        {
            for(i=1;i<=n;i++){
                scanf("%d",&w[i]);
                maxw[i]=minw[i]=w[i];
                up[i]=down[i]=0;
                pre[i]=i;
            }
            tot=0;
            memset(first,-1,sizeof(first));
            for(i=1;i<=n-1;i++){
                scanf("%d%d",&c,&d);
                e[i].next=first[c];e[i].to=d;
                first[c]=i;
    
                e[i+n-1].next=first[d];e[i+n-1].to=c;
                first[d]=i+n-1;
            }
    
            memset(h,-1,sizeof(h));
            scanf("%d",&q);
            for(i=1;i<=q;i++){
                scanf("%d%d",&uu[i],&vv[i]);
                int c=uu[i];
                int d=vv[i];
                question[i].to=d;question[i].idx=i;question[i].next=h[c];
                h[c]=i;
    
                question[i+q].to=c;question[i+q].idx=i;question[i+q].next=h[d];
                h[d]=i+q;
            }
            memset(vis,0,sizeof(vis));
            memset(h1,-1,sizeof(h1));
            tot=0;
            lca(1);
            for(i=1;i<=q;i++){
                printf("%d
    ",answer[i]);
            }
        }
        return 0;
    }
    


  • 相关阅读:
    unity3d热更新插件uLua学习整理
    结合axios对项目中的api请求进行封装
    移动端适配剖析
    vscode如何调试node项目(给node项目打断点)
    mac上使用cnpm搭建npm私有仓库,并上传/下载私有npm包
    前端常见的兼容性问题--web端和移动端
    react树形选择组(支持:单选,多选,全选)
    MongoDB 与 Mysql 的对比
    使用div 的 contenteditable属性,实现输入编辑,输入 "#" 出现下拉选择
    前端单元测试,以及给现有的vue项目添加jest + Vue Test Utils的配置
  • 原文地址:https://www.cnblogs.com/herumw/p/9464635.html
Copyright © 2011-2022 走看看