传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2870
看完就想到点分治了
可是用传统的点分治合并两条子树的链的时候很蛋疼……
于是我们换个方式
找到重心后把子树分成两堆,统计过根且起始结束位置在两个不同的堆里的答案
递归两堆子树
这种思想很早就有了 http://hi.baidu.com/345585690/item/fc3d0dd3167c28896cce3f09 http://blog.sina.com.cn/s/blog_76f6777d0101imnn.html
而且也不是很难写
如果把分治过程记录下来就可以做到动态修改询问,不过好像没人给这种数据结构起名字(或者我太弱了不知道)……
我就给它起名叫点分树了……
边分加虚点,括号序列什么的都太神了不会
好像树上点/链修改,整体/子树 路径查询的题不多……(QTREE有几个,wc,zjoi也有)
似乎可以有一大波新题诞生(又要被D了233)?
不过说起来这道题是静态的我在这扯什么蛋……
马上就去写1095
Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=50010;
int getint(){
int res=0;char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c))res=res*10+c-'0',c=getchar();
return res;
}
vector<int>G[maxn];
int n,f[maxn],siz[maxn],w[maxn],d[maxn],root,dep[maxn];
int cant[maxn];
long long ans;
void makert(int u,int All,int fa,int &root){
siz[u]=1;f[u]=0;
for(int i=0,v;i<G[u].size();i++){
if((v=G[u][i])==fa||cant[v])continue;
makert(v,All,u,root);
siz[u]+=siz[v];
f[u]=max(f[u],siz[v]);
}f[u]=max(f[u],All-f[u]);
if(f[root]>f[u])root=u;
}
int dsize,dsize2,tsize;
pair<int,int> data[maxn],data2[maxn];
pair<int,int> tmp[maxn];
void dfs(int u,int fa){
data[++dsize]=make_pair(d[u],dep[u]);
for(int i=0,v;i<G[u].size();i++){
if((v=G[u][i])==fa||cant[v])continue;
d[v]=min(w[v],d[u]);dep[v]=dep[u]+1;
dfs(v,u);
}
}
int cnt=0;
void solve(int u,int All){
int now=++cnt;
int root=0;f[root]=n+1;
makert(u,All,0,root);
makert(root,All,0,u);
int sum=0,can=0,used=0;
for(int i=0,v;i<G[u].size();i++)can+=!cant[v=G[u][i]];
if(can<=1)return;
for(int i=0,v;i<G[u].size();i++){
if(cant[v=G[u][i]])continue;
sum+=siz[v];cant[v]=now;used++;
if(sum>=(All+1)/2||used+1==can)break;
}dsize=0;dep[u]=0;d[u]=w[u];dfs(u,u);dsize2=dsize;
copy(data+1,data+1+dsize,data2+1);
for(int i=0,v;i<G[u].size();i++){
if(cant[v=G[u][i]]&&cant[v]!=now)continue;
cant[v]=now-cant[v];
}dsize=0;dep[u]=0;d[u]=w[u];dfs(u,u);tsize=0;
sort(data+1,data+1+dsize);
sort(data2+1,data2+1+dsize2);
int maxy=-1;
for(int i=dsize;i>=1;i--)
if(data[i].second>maxy)tmp[++tsize]=data[i],maxy=data[i].second;
copy(tmp+1,tmp+1+tsize,data+1);dsize=tsize;maxy=-1;tsize=0;
for(int i=dsize2;i>=1;i--)
if(data2[i].second>maxy)tmp[++tsize]=data2[i],maxy=data2[i].second;
copy(tmp+1,tmp+1+tsize,data2+1);dsize2=tsize;
sort(data+1,data+1+dsize);
sort(data2+1,data2+1+dsize2);
for(int i=1;i<=dsize;i++){
ans=max(ans,(long long)data[i].first*(data[i].second+1));
pair<int,int> *x=lower_bound(data2+1,data2+1+dsize2,make_pair(data[i].first,-1));
if(x==data2+1+dsize2)continue;
ans=max(ans,(long long)(data[i].second+x->second+1)*data[i].first);
}
for(int i=1;i<=dsize2;i++){
ans=max(ans,(long long)data2[i].first*(data2[i].second+1));
pair<int,int> *x=lower_bound(data+1,data+1+dsize,make_pair(data2[i].first,-1));
if(x==data+1+dsize)continue;
ans=max(ans,(long long)(data2[i].second+x->second+1)*data2[i].first);
}
if(sum+1>2)
solve(u,sum+1);
for(int i=0,v;i<G[u].size();i++){
if(cant[v=G[u][i]]&&cant[v]!=now)continue;
cant[v]=now-cant[v];
}if(All-sum>2)
solve(u,All-sum);
for(int i=0;i<G[u].size();++i)cant[G[u][i]]=cant[G[u][i]]==now?0:cant[G[u][i]];
}
int main(){
n=getint();
for(int i=1;i<=n;i++)w[i]=getint();
for(int i=1;i<n;i++){
int u=getint(),v=getint();
G[u].push_back(v);
G[v].push_back(u);
}solve(1,n);
cout<<ans<<endl;
return 0;
}