题解:UVA12161 铁人比赛 Ironman Race in Treeland
题解
考虑如果路径必须包含点 \(u\) 怎么做。
以 \(u\) 为根,求出每个点以代价为边权时的深度 \(D_v\) 和以收益为边权时的深度 \(L_v\),找到两个点 \(x,y\):
- \(x,y\) 属于根节点的不同子树;
- \(D_x+D_y \leq m\);
- \(L_x+L_y\) 最大。
把 \((D_x,L_x)\) 表示在坐标平面,可以发现任意一个点右下方的点可以直接删去(代价更大收益更小,肯定不会选)。
所以只需要用一个数据结构(STL)维护横纵坐标都严格递增的点列,并支持对某个 \((D_y,L_y)\) 查询最优的 \((D_x,L_x)\)。由于点列单调,查询的时候二分即可。
考虑完必须包含点 \(u\) 的情况,剩下的部分就是标准的点分治了。
代码
我用了 set<pair<int,int> > 实现,在维护点列的时候一定要想清楚!不然会像我一样错很多。
/*
* @Author: wanggk
* @Date: 2025-04-05 19:14:18
*/
#include<bits/stdc++.h>
#define For(i,il,ir) for(int i=(il);i<=(ir);++i)
#define Forr(i,ir,il) for(int i=(ir);i>=(il);--i)
#define ForE(u) for(int i=head[u];~i;i=e[i].nxt)
#define Spc putchar(' ')
#define End putchar('\n')
#define mk make_pair
using namespace std;
typedef long long ll;
template<typename T> inline void rd(T& x){ bool f=0;x=0;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=1; ch=getchar(); } while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); if(f) x=-x; }
template<typename T,typename... Args> void rd(T& first,Args&... args){ rd(first),rd(args...); }
template<typename T> inline void write(T x){ int write_num[50],len=0; if(x<0) putchar('-'),x=-x; do write_num[len++]=x%10; while(x/=10); while(len--) putchar(write_num[len]+'0'); }
template<typename T,typename... Args> void write(T first,Args... args){ write(first),Spc,write(args...); }
typedef pair<int,int> pii;
const int maxn=3e4+10;
void ckmax(int &x,int y){ x=(y>x?y:x); }
int n,m,res;
int head[maxn],cnt;
struct edge{ int v,nxt,d,l; }e[maxn<<1];
void add(int x,int y,int z1,int z2){ e[cnt]=(edge){y,head[x],z1,z2},head[x]=cnt++; }
int U,rt;
bool vis[maxn];
int c[maxn],sz[maxn];
#define v e[i].v
void getrt(int u,int fa){
sz[u]=1,c[u]=0;
ForE(u) if(v^fa && !vis[v]) getrt(v,u),sz[u]+=sz[v],ckmax(c[u],sz[v]);
ckmax(c[u],U-sz[u]);
if(rt==-1 || c[u]<c[rt]) rt=u;
}
multiset<pii> st;
void qry(int D,int L){
auto it=st.lower_bound(mk(m-D+1,0));
if(it==st.begin()) return;
ckmax(res,((--it)->second)+L);
}
void upd(int D,int L){
auto it0=st.lower_bound(mk(D+1,0));
if(it0!=st.begin() && (--it0)->second >= L) return;
auto itl=st.lower_bound(mk(D,0)),itr=itl;
while(itr!=st.end() && (itr->second)<=L) itr++;
st.erase(itl,itr),st.insert(mk(D,L));
}
int D[maxn],L[maxn],timer;
void dfs(int u,int fa,int sd,int sl){
D[++timer]=sd,L[timer]=sl;
if(sd<=m) res=max(res,sl);
ForE(u) if(v^fa && !vis[v])
dfs(v,u,sd+e[i].d,sl+e[i].l);
}
void divide(int u)
{
vis[u]=true;
ForE(u) if(!vis[v]){
timer=0,dfs(v,u,e[i].d,e[i].l);
For(k,1,timer) qry(D[k],L[k]);
For(k,1,timer) upd(D[k],L[k]);
}
st.clear();
ForE(u) if(!vis[v])
U=sz[v],rt=-1,getrt(v,u),divide(rt);
}
void solve(){
rd(n,m); memset(head,-1,sizeof(head));
for(int i=2,x,y,z,w;i<=n;i++) rd(x,y,z,w),add(x,y,z,w),add(y,x,z,w);
U=n,rt=-1,getrt(1,0);divide(rt);
}
void clear(){ cnt=res=0; For(i,1,n) vis[i]=false; }
signed main(){
int T;rd(T);
For(tt,1,T){ solve(); printf("Case %d: %d\n",tt,res); clear(); }
return 0;
}

浙公网安备 33010602011771号