Link:题目
就是说上次我说的那个PKU月赛题。。Tarjan离线就是NB啊。。
那个保存2的乘方的既耗空间,又耗时间。。
而Tarjan是线性的。。
这道题目就是说给你一个颗边不代权,点代权的树,有个商人要旅行。每次从一个点到另一个点,点权表示商品的价格。。商人最多进货和卖出一次,求他的最大收入(可以不交易)。。
这道题就需要维护一个并查集中顶点到并查集中父亲的路径的4个值了,最大点权,最小点权,从它到并查集中父亲一路的最大收入,从并查集父亲到它一路的最大收入。。
这是可以合并的。。然后求的时候。。终点到lca的信息要反一下。。
Code:
#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
#define pb push_back
#define rep(i,n) for(int i=0;i<n;i++)
using namespace std;
const int inf=1<<20;
const int maxn=50000;int n;
const int maxm=maxn;int m;
struct edge
{
int t;
edge(int _t):t(_t){}
};
struct queryLca
{
bool s;
int t,n;
queryLca(int _t,int _n,bool _s):t(_t),n(_n),s(_s){}
};
struct query
{
int a,b,n;
query(int _a,int _b,int _n):a(_a),b(_b),n(_n){}
};
struct info
{
int Min,Max,Pro,RPro;
info(int v=0):Min(v),Max(v),Pro(0),RPro(0){}
info R()
{
info ans=*this;
swap(ans.Pro,ans.RPro);
return ans;
}
void Merge(const info& o)
{
Pro=max(Pro,o.Pro);
Pro=max(Pro,o.Max-Min);
RPro=max(RPro,o.RPro);
RPro=max(RPro,Max-o.Min);
Min=min(Min,o.Min);
Max=max(Max,o.Max);
}
};
vector<edge> E[maxn];
vector<queryLca> Lca[maxn];
vector<query> Query[maxn];
typedef vector<edge>::iterator eit;
typedef vector<queryLca>::iterator lit;
typedef vector<query>::iterator qit;
info Ans[maxm];
void add_edge(int s,int t)
{
E[s].pb(edge(t));
E[t].pb(edge(s));
}
void add_lca(int s,int t,int n)
{
Lca[s].pb(queryLca(t,n,true));
Lca[t].pb(queryLca(s,n,false));
}
info P[maxn];
int F[maxn];
void set()
{
rep(i,n) F[i]=i;
}
int find(int x)
{
int tmp=F[x];
if(F[x]!=x)
F[x]=find(F[x]),P[x].Merge(P[tmp]);
return F[x];
}
void Union(int i,int j)
{
F[j]=i;
}
bool vis[maxn]={0};
void dfs(int x)
{
vis[x]=true;
for(eit i=E[x].begin();i!=E[x].end();i++)if(!vis[i->t])
dfs(i->t),Union(x,i->t);
for(lit i=Lca[x].begin();i!=Lca[x].end();i++)
{
if(vis[i->t])
{
if(i->s)
Query[find(i->t)].pb(query(x,i->t,i->n));
else
Query[find(i->t)].pb(query(i->t,x,i->n));
}
}
for(qit i=Query[x].begin();i!=Query[x].end();i++)
{
find(i->a);find(i->b);
info&t=Ans[i->n];
t=P[i->a];t.Merge(P[i->b].R());
}
}
void init()
{
scanf("%d",&n);int s,t,c;
set();
for(int i=0;i<n;i++)
scanf("%d",&c),P[i]=info(c);
for(int i=0;i<n-1;i++)
{
scanf("%d %d",&s,&t);
add_edge(s-1,t-1);
}
scanf("%d",&m);int a,b;
for(int i=0;i<m;i++)
{
scanf("%d %d",&a,&b);
add_lca(a-1,b-1,i);
}
}
void solve()
{
dfs(0);
for(int i=0;i<m;i++)
printf("%dn",Ans[i].Pro);
}
int main()
{
//freopen("in","r",stdin);
//freopen("out","w",stdout);
init();
solve();
}
本高亮代码使用codeHl生成,