您的位置:首页 > 其它

POJ 3728 The merchant 离线tarjan

2017-10-10 14:16 302 查看

题目链接

http://poj.org/problem?id=3728

题意

一件商品在每个城市的价格都不一样,某个商人决定利用这个来赚钱,他想知道从某个起点到某终点,可以获得的最大利润。总共q次询问。

思路

对于询问中的u和v,lca为u和v的最近公共祖先

up[u] 表示从u往lca方向走能获得的最大利润

down[u]表示从lca方向往u走能获得的最大利润

Max[u] 表示从u到lca这段路径中的最大值

Min[u] 表示从u到lca这段路径中的最小值

这些值的更新是在找祖先的过程中更新

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define ll long long
using namespace std;
const int INF = ( 2e9 ) + 2;
const ll maxn = 5e4+10;
struct edge
{
int u,v,next;
}e[2*maxn],que[2*maxn],l[2*maxn];
int head1[maxn],head2[maxn],head3[maxn];
int tot1,tot2,tot3;
int ans[maxn];
int Max[maxn],Min[maxn],up[maxn],down[maxn],f[maxn];
bool vis[maxn];
void init()
{
memset(head1,-1,sizeof(head1));
memset(head2,-1,sizeof(head2));
memset(head3,-1,sizeof(head3));
tot1=tot2=tot3=0;
}
void add_edge(int u,int v)
{
e[tot1].v=v;
e[tot1].next=head1[u];
head1[u]=tot1++;
}
void add_que(int u,int v)
{
que[tot2].u=u;
que[tot2].v=v;
que[tot2].next=head2[u];
head2[u]=tot2++;
}
void add_lca(int u,int v)
{
l[tot3].v=v;
l[tot3].next=head3[u];
head3[u]=tot3++;
}
int Find(int x)
{
if(f[x]==x)return x;
int p=f[x];
f[x]=Find(f[x]);
up[x]=max(up[x],max(up[p],Max[p]-Min[x]));
down[x]=max(down[x],max(down[p],Max[x]-Min[p]));
Max[x]=max(Max[x],Max[p]);
Min[x]=min(Min[x],Min[p]);
return f[x];
}
int input(int n)
{
int u,v,q;
for(int i=1;i<=n;i++)
{
scanf("%d",&Max[i]);
Min[i]=Max[i];
up[i]=down[i]=0;
}
init();
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&u,&v);
add_que(u,v);
add_que(v,u);
}
return q;
}
void tarjan(int u)
{
f[u]=u;
vis[u]=true;
int v;

for(int i=head2[u];i!=-1;i=que[i].next)
{
v=que[i].v;
if(vis[v])
{
int LCA=Find(v);
add_lca(LCA,i);
}
}

for(int i=head1[u];i!=-1;i=e[i].next)
{
v=e[i].v;
if(!vis[v])
{
tarjan(v);
f[v]=u;
}
}

for(int i=head3[u];i!=-1;i=l[i].next)
{
int id=l[i].v;
if((id&1))id=id^1;
int u=que[id].u,v=que[id].v;
Find(u);
Find(v);
int t=id/2; // 答案要不是在u->lca 这一段中 要不就在lca->v 中,要不就跨越了lca
ans[t]=max(up[u],down[v]);
ans[t]=max(ans[t],Max[v]-Min[u]);
}
}
void solve(int q)
{
memset(vis,0,sizeof(vis));
tarjan(1);
for(int i=0;i<q;i++)
printf("%d\n",ans[i]);
}
int main()
{
int n;
//  freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
int q=input(n);
solve(q);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: