1. 程式人生 > 其它 >luogu P8274 [USACO22OPEN] Balancing a Tree G

luogu P8274 [USACO22OPEN] Balancing a Tree G

題面傳送門
感覺一道比較精妙的題目。但是我的做法好像很暴力
首先考慮確定根節點權值以後怎麼做。
對於每個節點,考慮其到根的路徑上的節點,可以發現只有最大值和最小值是有用的。
這個點的取值只有三種情況:左端點,右端點,最大值和最小值的中值(如果在這個區間裡的話)。
等等,我們好像沒有考慮對下面點的影響?
實際上只要這個點最優,對下面的影響就最小。因為最後一種對最大值和最小值是沒有影響,可以忽略。前兩種取到最優的時候恰好是對最大最小值影響最低的時候。
然後剩下根節點的取值,發現看上去一臉三分,然後就過了。
時間複雜度\(O(n\log W)\)
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 ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M (900+5)
#define K (200000+5)
#define mod 9248440332
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;vector<int> S[N];
int n,m,k,x,y,z,T,B,H,L[N],R[N],P[N],l,r,m1,m2,Ans,Pus;
struct Ques{int x,w;}Q[4];I bool cmp(Ques x,Ques y){return x.w<y.w;}
I void dfs(int x,int Mx,int Mi){
	H=0;Q[++H]=(Ques){L[x],max(abs(L[x]-Mx),abs(L[x]-Mi))};Q[++H]=(Ques){R[x],max(abs(R[x]-Mx),abs(R[x]-Mi))};(Mx+Mi)/2>=L[x]&&(Mx+Mi)/2<=R[x]&&(Q[++H]=(Ques){(Mx+Mi)/2,(Mx-Mi+1)/2},0);
	sort(Q+1,Q+H+1,cmp);P[x]=Q[1].x;Pus=max(Pus,Q[1].w);for(int i:S[x]) dfs(i,max(Mx,P[x]),min(Mi,P[x]));
}
I int CK(int mid){Pus=0;P[1]=mid;for(int i:S[1]) dfs(i,P[1],P[1]);return Pus;}
I void Solve(){
	int i;for(i=1;i<=n;i++) S[i].clear();scanf("%d",&n);for(i=2;i<=n;i++) scanf("%d",&x),S[x].PB(i);for(i=1;i<=n;i++) scanf("%d%d",&L[i],&R[i]);
	l=L[1];r=R[1];while(l+2<r) m1=l+(r-l)/3,m2=r-(r-l)/3,CK(m1)<CK(m2)?(r=m2):(l=m1);Ans=1e9;for(i=l;i<=r;i++) x=CK(i),Ans=min(Ans,x);
	//cerr<<' '<<CK(1)<<'\n';
	printf("%d\n",Ans);if(!B) return;for(i=l;i<=r;i++) if(CK(i)==Ans) {printf("%d ",i);break;}for(i=2;i<=n;i++) printf("%d ",P[i]);Pc('\n');
}
int main(){
	freopen("1.in","r",stdin);
	scanf("%d%d",&T,&B);while(T--) Solve();
}