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;
    }
    


  • 相关阅读:
    python的几个实例程序员节日快乐
    用python的time库写一个进度条
    用python绘画一些简单图片
    头文件板子
    Codeforces 606-C:Sorting Railway Cars(LIS)
    中南林业科技大学第十一届程序设计大赛- I:背包问题
    离散数学:用C语言来判断集合存在的二元关系
    中南林业科技大学第十一届程序设计大赛-C:有趣的二进制
    POJ 1611:The Suspects(并查集)
    POJ 2236:Wireless Network(并查集)
  • 原文地址:https://www.cnblogs.com/herumw/p/9464635.html
Copyright © 2011-2022 走看看