题解: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;
}

浙公网安备 33010602011771号