poj3728並查集+LCA

題目大意:
對於一棵樹,樹上的每點都有一個權值,對於一個詢問u,v,求從u 點到v點的路徑上進行買賣所能得到的最大值,並且,買在賣之前。
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 ≤ N, wi, Q ≤ 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

思路:
設u,v的公共祖先爲r,那麼路徑上能夠得到的最大值有三種取值情況;
1,在u到r的路徑上取得,即完成一次買賣;
2,在r到v的路徑上取得,即完成一次買賣;
3,買發生在u到r的路徑上,賣發生在r到v的路徑上;
那麼我們需要在整個過程中維護的值有:
up[x]:從x到r的一個上升路徑上的能夠得到的利潤最大值;
down[x]:從x到r的一個下降路徑上能夠得到的利潤最大值;
mx[x]:從x到r的路徑上各節店權值的最大值;
mi[x]:從x到r的路徑上各節店權值的最小值;
而上述值,將會在並查集的路徑壓縮過程中維護更新;

將每一個詢問,都歸結到LCA,那麼當LCA的整個子樹遍歷完成後,才能計算結果;

此代碼參考了別人:

#include <bits/stdc++.h>
using namespace std;
const int maxn=50009;
vector<int> g[maxn],st[maxn],ed[maxn],ask[maxn],pos[maxn],id[maxn];
int mx[maxn],mi[maxn],up[maxn],down[maxn],vis[maxn],fa[maxn],ans[maxn];
int n,q;
int find(int x)
{
    if(x==fa[x]) return x;
    int y=fa[x];
    fa[x]=find(y);
    up[x]=max(up[x],max(mx[y]-mi[x],up[y]));
    down[x]=max(down[x],max(mx[x]-mi[y],down[y]));
    mx[x]=max(mx[x],mx[y]);
    mi[x]=min(mi[x],mi[y]);
    return fa[x];
}
void tarjan(int u)
{
    vis[u]=1;
    for(int i=0;i<ask[u].size();i++)
    {
        int v=ask[u][i];
        if(vis[v])
        {
            int t=find(v);
            int z=pos[u][i];
            if(z>0)
            {
                st[t].push_back(u);
                ed[t].push_back(v);
                id[t].push_back(z);
            }
            else
            {
                st[t].push_back(v);
                ed[t].push_back(u);
                id[t].push_back(-z);
            }
        }
    }
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(!vis[v])
        {
            tarjan(v);
            fa[v]=u;
        }
    }
    for(int i=0;i<st[u].size();i++)
    {
        int a=st[u][i];
        int b=ed[u][i];
        int t=id[u][i];
        find(a);
        find(b);
        ans[t]=max(up[a],max(down[b],mx[b]-mi[a]));
    }
}
int main()
{
    scanf("%d",&n);
    int u,v,w;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&w);
        mx[i]=mi[i]=w;fa[i]=i;
    }
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&u,&v);
        ask[u].push_back(v);
        pos[u].push_back(i);
        ask[v].push_back(u);
        pos[v].push_back(-i);
    }
    tarjan(1);
    for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
    return 0;
}
發佈了174 篇原創文章 · 獲贊 64 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章