1. 程式人生 > 其它 >2019.7.13 義烏模擬賽 T3 tree

2019.7.13 義烏模擬賽 T3 tree

看到這種平均數的題目肯定想到分數規劃啊。
首先二分一個\(mid\),然後每個點的點權減去\(mid\),就變成了對於每個點求樹上的包含一個點的連通塊最大大小。
這個顯然是平凡換根dp首先一邊dp弄出子樹內,然後再來一次算父親的貢獻。
時間複雜度\(O(nlogk)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 100000
#define M 500000
#define mod 1000000007
#define eps (1e-8)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,k,x,A[N+5];db l,r,mid,dp[N+5],H[N+5],B[N+5],ans;
vector<int> S[N+5];vector<db> Q1[N+5],Q2[N+5];
I void dfs1(int x){
	int now;dp[x]=B[x];for(int i=0;i<S[x].size();i++)now=S[x][i],dfs1(now),dp[x]+=max(dp[now],0); 
}
I void dfs2(int x){
	int i,now;ans=min(ans,dp[x]+H[x]);for(i=0;i<S[x].size();i++) Q1[x][i]=Q2[x][i]=max(dp[S[x][i]],0);for(i=1;i<S[x].size();i++) Q1[x][i]+=Q1[x][i-1];for(i=S[x].size()-2;i>=0;i--) Q2[x][i]+=Q2[x][i+1];
	for(i=0;i<S[x].size();i++) now=S[x][i],H[now]=max(H[x]+(i?Q1[x][i-1]:0)+(i<S[x].size()-1?Q2[x][i+1]:0)+B[x],0),dfs2(now);
}
I int check(db mid){
	re int i;for(i=1;i<=n;i++) B[i]=A[i]-mid;dfs1(1);ans=1e9;dfs2(1);return ans>=0;
}
int main(){
	freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);
	re int i;scanf("%d",&n);for(i=1;i<=n;i++)scanf("%d",&A[i]),r=max(r,A[i]);r+=eps;for(i=2;i<=n;i++) scanf("%d",&x),S[x].push_back(i),Q1[x].push_back(0),Q2[x].push_back(0);
	while(l+eps<r) mid=(l+r)/2,(check(mid)?l:r)=mid; printf("%.8lf\n",l);
}