点分治处理不了最小值
边分治,和点分治类似,就是选择一条边,使其两端的子树最大的最小
然后一样容易被卡(菊花图)
所以把树建成一棵二叉树,如果一个点的儿子大于2个就建两个新点管理它的儿子,如果还多于两个就继续建(和线段树一样)这样保证了复杂度
那么考虑这道题:最小值用边分治显然就很好处理了,然后我们把新建的边的权值赋为0,原边的权值为1,那么两点之间的点数就是边权和+1
那么我们对于每次分治,可以把左右的拿出来分别排序,然后在另一边找到最小值大于它的最长的一条更新答案
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=2e5+5,INF=0x3f3f3f3f;
int vis[N<<1],head[N],c[N],nxt[N<<1],tot=0;
inline void add(int x,int y,int z){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;c[tot]=z;}
vector<int>e[N];
int n,kn,rt,maxn;
int val[N];
void dfs(int v,int fa){
for(int i=head[v];i;i=nxt[i])
if(vis[i]!=fa) e[v].push_back(vis[i]),dfs(vis[i],v);
}
inline void rebuild(){
tot=1;memset(head,0,sizeof(head));
for(int i=1;i<=n;i++){
int siz=e[i].size();
if(siz<=2) for(int j=0;j<siz;j++) add(i,e[i][j],(e[i][j]<=kn)),add(e[i][j],i,(e[i][j]<=kn));
else{
int o1=++n,o2=++n;
val[o1]=val[o2]=val[i];
add(i,o2,0);add(o2,i,0);
add(i,o1,0);add(o1,i,0);
for(int j=0;j<siz;j++){
if(j&1) e[o2].push_back(e[i][j]);
else e[o1].push_back(e[i][j]);
}
}
}
}
int siz[N],pt[N];
void getroot(int v,int fa,int S){
siz[v]=1;
for(int i=head[v];i;i=nxt[i]){
if(pt[i>>1] || vis[i]==fa) continue;
getroot(vis[i],v,S);
siz[v]+=siz[vis[i]];
int res=max(siz[vis[i]],S-siz[vis[i]]);
if(res<maxn) maxn=res,rt=i;
}
}
struct node{int v,len;}t[2][N];
inline bool cmp(node a,node b){return a.v>b.v;}
int cnt[2];
void solve(int v,int fa,int len,int V,int num){
V=min(V,val[v]);t[num][++cnt[num]]=(node){V,len};
for(int i=head[v];i;i=nxt[i]){
if(pt[i>>1] || vis[i]==fa) continue;
solve(vis[i],v,len+c[i],V,num);
}
}
ll ans=0;
void work(int v,int S){
maxn=INF;getroot(v,0,S);
if(maxn==INF) return;
int now=rt;pt[now>>1]=1;
cnt[0]=cnt[1]=0;
solve(vis[now],0,0,INF,0);
solve(vis[now^1],0,0,INF,1);
sort(t[0]+1,t[0]+cnt[0]+1,cmp);
sort(t[1]+1,t[1]+cnt[1]+1,cmp);
for(int i=1,j=1,maxx=0;i<=cnt[0];i++){
while(j<=cnt[1] && t[1][j].v>=t[0][i].v) maxx=max(maxx,t[1][j].len),++j;
if(j!=1) ans=max(ans,1ll*t[0][i].v*(maxx+t[0][i].len+c[now]+1));
}
for(int i=1,j=1,maxx=0;i<=cnt[1];i++){
while(j<=cnt[0] && t[0][j].v>=t[1][i].v) maxx=max(maxx,t[0][j].len),++j;
if(j!=1) ans=max(ans,1ll*t[1][i].v*(maxx+t[1][i].len+c[now]+1));
}
int kk=siz[vis[now]];
work(vis[now],kk);
work(vis[now^1],S-kk);
}
int main(){
n=kn=read();
for(int i=1;i<=n;++i) val[i]=read();
for(int x,y,i=1;i<n;++i) x=read(),y=read(),add(x,y,1),add(y,x,1);
dfs(1,0),rebuild(),work(1,n);
cout<<ans<<"\n";
return 0;
}