题目传送门
题目大意: 给一棵树,每个点有点权,一条路径的贡献为路径上最小的点权
× \times ×路径上的点数
,找出贡献最大的路径的贡献。
考虑边分治,重构树时,虚点的点权设为所在子树树根的点权,然后考虑将路径上的点数
转化为路径上的边数+1
,然后将实边边权设为 1 1 1,虚边边权设为 0 0 0。
求解时,每次将重心边左右两棵子树的点分别存下来,并且存下他们到重心边路径上的边权和以及最小点权,分别记在两个数组 f 1 , f 2 f_1,f_2 f1,f2 中,将其中的点按照最小点权从大到小排序,然后对于 f 1 [ i ] f_1[i] f1[i],考虑其作为整条路径上最小点权的情况,此时要在 f 2 f_2 f2 中找到所有点权大于 f 1 [ i ] f_1[i] f1[i] 的点的最大边权和,然后和 f 1 [ i ] f_1[i] f1[i] 凑在一起更新一下答案。
由于 f 1 , f 2 f_1,f_2 f1,f2 都排了序,所以很容易知道 f 2 f_2 f2 中点权小于 f 1 [ i ] f_1[i] f1[i] 的点的最大边权和,然后将 f 1 , f 2 f_1,f_2 f1,f2 反过来再做一次即可,具体看代码吧:
#include
#include
using namespace std;
#define maxn 200010 //
#define inf 999999999
#define ll long long
int n,val[maxn],real[maxn];
struct V_E{
struct edge{int x,y,z,next;bool v;}e[maxn<<1];
int first[maxn],len;V_E():len(1){}
void buildroad(int x,int y,int z){e[++len]=(edge){x,y,z,first[x],false};first[x]=len;}
void ins(int x,int y,int z){buildroad(x,y,z);buildroad(y,x,z);}
}A,B;
void rebuild(int x,int fa)
{
int last=0,New;
for(int i=A.first[x];i;i=A.e[i].next)
{
int y=A.e[i].y;if(y==fa)continue;
rebuild(y,x);if(!last)last=x,B.ins(x,y,1);
else val[New=++n]=val[x],B.ins(last,New,0),B.ins(New,y,1),last=New;
}
}
int size[maxn],E,vE;
void findE(int x,int fa,int Size)
{
size[x]=1;
for(int i=B.first[x];i;i=B.e[i].next)
{
int y=B.e[i].y;if(B.e[i].v||B.e[i].y==fa)continue;
findE(y,x,Size);size[x]+=size[y];
int mx=max(size[y],Size-size[y]);
if(mx<vE)vE=mx,E=i;
}
}
struct par{int mi,len;}a[maxn],b[maxn];ll ans=0;
void work(par *f1,int &t1,par *f2,int &t2,int now_E)
{
int mx=0;
for(int i=1,j=1;i<=t1;i++){
while(j<=t2&&f2[j].mi>=f1[i].mi)mx=max(mx,f2[j].len),j++;
if(j>1)ans=max(ans,1ll*(mx+f1[i].len+1+B.e[now_E].z)*f1[i].mi);
}
}
int t1,t2;void dfs(par *f,int &t,int x,int fa,int mi,int dep)
{
mi=min(mi,val[x]);f[++t]=(par){mi,dep};
for(int i=B.first[x];i;i=B.e[i].next)
if(B.e[i].y!=fa&&!B.e[i].v)dfs(f,t,B.e[i].y,x,mi,dep+B.e[i].z);
}
bool cmp(par x,par y){return x.mi>y.mi;}
void solve(int now_E)
{
dfs(a,t1=0,B.e[now_E].x,0,inf,0);
dfs(b,t2=0,B.e[now_E].y,0,inf,0);
sort(a+1,a+t1+1,cmp);sort(b+1,b+t2+1,cmp);
work(a,t1,b,t2,now_E);work(b,t2,a,t1,now_E);
}
void fenzhi(int now_E,int Size)
{
B.e[now_E].v=B.e[now_E^1].v=true;solve(now_E);
int x=B.e[now_E].x,y=B.e[now_E].y;
int Size1=(size[x]<size[y]?size[x]:Size-size[y]);
int Size2=(size[y]<size[x]?size[y]:Size-size[x]);
E=0;vE=inf;findE(B.e[now_E].x,0,Size1);if(E)fenzhi(E,Size1);
E=0;vE=inf;findE(B.e[now_E].y,0,Size2);if(E)fenzhi(E,Size2);
}
//-----------------------------------------------------------------
inline char cn()
{
static char buf[1000010],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
//#define cn getchar
template<class TY>void read(TY &x)
{
x=0;int f1=1;char ch=cn();
while(ch<'0'||ch>'9'){if(ch=='-')f1=-1;ch=cn();}
while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=cn(); x*=f1;
}
int main()
{
read(n); for(int i=1;i<=n;i++)read(val[i]),real[i]=1;
for(int i=1,x,y;i<n;i++)read(x),read(y),A.ins(x,y,0);rebuild(1,0);
E=0;vE=inf;findE(1,0,n);fenzhi(E,n);printf("%lld",ans);
}