题解:UVA12161 铁人比赛 Ironman Race in Treeland

题目传送门

思路:

与众不同的做法:二次扫描+分块。

询问总费用不超过 \(m\),最长的路径。

先以 \(1\) 为根求出每个点到 \(1\) 的距离与费用,对费用和距离进行分块,每个块内按照费用升序排序,维护块内排序后距离的前缀最大值,询问时对每个块二分出最长位置,每个块的答案取最大就行。

换根这一步也很简单,对于 \((u,v,L,D)\) 这条边,我们的根 \(u\rightarrow v\)\(v\) 子树内的点到根的距离和费用分别减少 \(L\)\(D\) 的,除 \(v\) 子树外的点到根的距离和费用分别增加 \(L\)\(D\),每个块维护两个 tag,整块 tag 加减,散块暴力修改重构。

询问和修改都是 \(O(n\sqrt n \log{\sqrt n})\) 的,所以复杂度为 \(O(n\sqrt n\log n)\),对于本题 \(n\le 3\times 10^4\) 的数据没啥压力。当然,块长取 \(\sqrt{n\over \log n}\) 时理论复杂度最优,为 \(O(n\sqrt{n\log n})\)

code

const int N=3e4+10,M=350;
struct edge{int to,Len,Val;};
vector<edge>G[N];
int Be[N],L[M],R[M],AddD[M],AddL[M],Ma[N];
int Dis[N],Len[N],H[N];
int PID[N],t=0;
int dfn[N],o=0,ID[N];
int m,n,Siz[N];
inline bool cmp(int l,int r)
{
	return Dis[l]<Dis[r];
}
inline void rebuild(int now)
{
	sort(PID+L[now],PID+R[now]+1,cmp);
	Ma[L[now]]=Len[PID[L[now]]];H[L[now]]=Dis[PID[L[now]]];
	for(int i=L[now]+1;i<=R[now];i++)
		Ma[i]=max(Ma[i-1],Len[PID[i]]),H[i]=Dis[PID[i]];
	return;
}
void modify(int l,int r,int val,int len)
{
	if(l==1&&r==n){
		for(int i=1;i<=t;i++)
			AddD[i]+=val,AddL[i]+=len;
		return;
	}
	if(Be[l]==Be[r]){
		for(int i=l;i<=r;i++)
			Dis[ID[i]]+=val,Len[ID[i]]+=len;
		rebuild(Be[l]);
	}
	else{
		for(int i=l;i<=R[Be[l]];i++)
			Dis[ID[i]]+=val,Len[ID[i]]+=len;
		for(int i=L[Be[r]];i<=r;i++)
			Dis[ID[i]]+=val,Len[ID[i]]+=len;
		rebuild(Be[l]),rebuild(Be[r]);
		for(int i=Be[l]+1;i<=Be[r]-1;i++)
			AddD[i]+=val,AddL[i]+=len;
	}
	return;
}
int Ans=0;
void query()
{
	for(int i=1;i<=t;i++)
	{
		int pos=upper_bound(H+L[i],H+R[i]+1,m-AddD[i])-(H+1);
		if(pos<L[i]) continue;
		Ans=max(Ans,Ma[pos]+AddL[i]);
	}
}
void dfs(int now,int from)
{
	ID[dfn[now]=++o]=now;Siz[now]=1;
	for(auto [to,len,val]:G[now])
	{
		if(to==from) continue;
		Len[to]=Len[now]+len,Dis[to]=Dis[now]+val;
		dfs(to,now);
		Siz[now]+=Siz[to];
	}
	return;
}
void redfs(int now,int from)
{
	query();
	for(auto [to,Len,Val]:G[now])
	{
		if(to==from) continue;
		modify(1,n,Val,Len),modify(dfn[to],dfn[to]+Siz[to]-1,-2*Val,-2*Len);
		redfs(to,now);
		modify(1,n,-Val,-Len),modify(dfn[to],dfn[to]+Siz[to]-1,2*Val,2*Len);
	}
}
void build()
{
	int len=sqrt(n);t=(n/len)+bool(n%len);
	for(int i=1;i<=n;i++) Be[i]=(i-1)/len+1;
	for(int i=1;i<=t;i++)
	{
		L[i]=R[i-1]+1,R[i]=min(R[i-1]+len,n);
		for(int j=L[i];j<=R[i];j++) PID[j]=ID[j];
		rebuild(i);
	}
	return;	
}
int main()
{
	int T=1;
	read(T);
	for(int i=1;i<=T;i++)
	{
		read(n,m);
		for(int i=1,x,y,z,w;i<n;i++)
		{
			read(x,y,z,w);
			G[x].push_back({y,w,z});
			G[y].push_back({x,w,z});
		}
		dfs(1,0),build(),redfs(1,0);
		write("Case ",i,": ",Ans,'\n');Ans=0;o=0;
		for(int i=1;i<=n;i++) G[i].clear();
		for(int i=1;i<=t;i++) AddD[i]=AddL[i]=0;
	}
    return 0;
}
posted @ 2024-11-08 14:47  EityDawn  阅读(41)  评论(0)    收藏  举报