传送门: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; }