AC不是我们的终极目标,我们的终极目标是获得经验。
题目大意:
一颗树,告诉你一个值的求法,让你在树的直径上选择一段路径使得这值最小
题目中的“值”:
在直径上选择一段路程F,这个值就是所有点到达F的最大值
首先介绍O(N^3)的解法:
适用于非加强版,数据范围N<=300
看到N<=300,我过去就是个flody嗷,什么dfs,树形dp求树的直径,lj
三层for之后
我们在任意两点之间选择最长的,并记录端点值
这时候树的直径和直径的两个端点就知道了
然后我们要在树的直径上选择一段路程F。
假设路程端点为pos1,pos2。 直径的端点为u,v,直径为maxlen
那么我们如何判断这个一段路程F是否在直径上?
那肯定是
f[pos1][pos2]+f[v][pos2]+f[u][pos1]==maxlen
就是这样,很简单吧
然后我们去求他题目中的值----偏心距
我们枚举路径F之外的点k
因为偏心距的定义是到F的最大值
这个点k到F的距离怎么求呢
那肯定是
t = max --> f[i][k]+f[j][k]-f[i][j])/2
然后再在所有的t中取一个最小值就ok了
O(NlogN)的解法:
最大值最小化–我过去就是一个二分嗷
老套路了
满足单调性:
简单再说下,如果答案mid作为最大值可以,那么mid+1一定也满足条件(说了跟没说一个样? )
显然我们这里需要二分答案mid
我们考虑如何O(n)的check
和解法一一致:
假设路程端点为pos1,pos2。 直径的端点为u,v,直径为maxlen
假设图是这样的
假设我们选出的路径是F
那么我们需要对F上的每个点都dfs一遍求得一个max
但是我们之前说过
要在O(n)的时间复杂度呢check
也就是说,每个点只走一次
我们发现:
在直径u-v这条链上的所有的点除了端点。都不会对答案产生贡献
什么意思呢?
我们看k这个点,他到路径F的距离会被直径的左端点代替,因为到左端点更大
对于直径这条链上的所有的点(除了端点)都是如此
那么我们只需要扫支链就可以了
枚举pos1到pos2之间的每个点,求到所有支链上的最大值,如果大于mid,就是不行的
好了,时间复杂度我们能够保证了
还有个小的问题就是pos1和pos2的位置如何确定?
首先我们要保证pos1和pos2之间的距离小于等于s(限制条件)
看上面那张图
根据直径的最长性,任何从 u, p 之间分叉离开直径的子树,其最远点与 p 的距离都不会比 u 更远。所以 p, q就是在满足直径两侧的那部分节点偏心距不超过 mid 的前提下,尽量靠近树网中心的节点。
剩下的就是一些细节方面的操作了
O(n)的解法:
经过上面两种解法的熏陶
我们直接快进好吧
快进到 知道树的直径的长度和一个端点
我们分为两种情况讨论:
一 直径的长度小于等于限制长度
还拿这张图来说
因为直径的长度小于等于限制的长度
所以我直径上任意取两个点pos1,pos2都能够满足条件
这个时候对答案产生贡献的只有端点,因为到支链的点的长度一定小于到端点的(不然直径的两端点就换了)
如果我pos1 ,pos2取在图上的位置
然后对两端点取一个max
这个时候就不如这样(下图)
仔细一想,我直接把pos1和pos2直接取到端点不就行了嘛,这样ans就等于0 了啊。
但是答案肯定不是0啊,应该是支链上的某一点到路径F的距离了
我们此时把整条直径都标记起来,然后跑一遍支链的所有的点到直径的距离,直接取一个最大就是答案
二 一直径的长度大于限制长度
此时,我们不能像做法一一样完全的标记直径
所以要尺取(不会证明正确性 )但是感觉就是可以
然后对答案产生贡献的还是端点(上面说过了)
这个时候对两个端点的贡献取一个max
然后再跟答案取一个min就ok了
有时候可以用一个dfs函数实现的功能我给分开写,所以代码略显冗余
Code_n^3:
int n,f[666][666],s;
int main() {
ios::sync_with_stdio(false);
cin>>n>>s;
rep(i,1,n) rep(j,1,n) f[i][j] = 1e7;
rep(i,1,n) f[i][i] =0;
for(int i=1 ; i<=n-1 ; i++) {
int u,v,w;
cin>>u>>v>>w;
f[u][v] = f[v][u] = w;
}
rep(k,1,n) rep(i,1,n) rep(j,1,n) f[i][j] = min(f[i][j],f[i][k]+f[k][j]);
int pos1,pos2,maxlen = -1;
for(int i=1 ; i<=n ; i++) {
for(int j=1 ; j<=n ; j++) {
if(f[i][j]>maxlen) {
pos1 = i,pos2 = j,maxlen = f[i][j];
}
}
}
int ans = 1e7;
for(int i=1 ; i<=n ; i++) {
for(int j=1 ; j<=n ; j++) {
if(f[i][j]+f[j][pos2]+f[i][pos1]!=maxlen) continue;
if(f[i][j]>s) continue;
int temp =-1;
for(int k=1; k<=n ; k++) {
temp = max(temp,(f[i][k]+f[j][k]-f[i][j])/2 );
}
ans = min(ans,temp);
}
}
cout<<ans;
Code_nlogn:
int head[maxn],cnt;
struct node {
int u,v,w,next;
} e[maxn];
void add(int u,int v,int w) {
e[cnt].u=u,e[cnt].v=v,e[cnt].w=w;
e[cnt].next=head[u],head[u]=cnt++;
}
int n,s,pos,mi,vis[maxn],fa[maxn],dist[maxn];
void dfs(int u,int p) {
fa[u] = p;
if(dist[u]>mi) mi = dist[u],pos = u;
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].v;
if(v==p) continue;
dist[v] = dist[u] + e[i].w;
dfs(v,u);
}
}
int ma = -1,dis[maxn];
void dfs_max(int u,int p) {
ma = max(ma, dis[u]);
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].v;
if(v==p||vis[v]) continue;
dis[v] = dis[u] + e[i].w;
dfs_max(v,u);
}
}
int ok(int x) {
int pos1=0 ,pos2 =0 ;
for(int i = pos ; i ; i = fa[i]) {
if(dist[pos] - dist[i]<=x) pos1 = i;
else break;
}
for(int i = pos ; i ; i = fa[i]) {
if(dist[i]<=x) {
pos2 = i;
break;
}
}
mst(dis,0);
if( dist[pos1] - dist[pos2]>s) return 0;
else if(dist[pos1] - dist[pos2]<=0) {
for(int i=pos1 ; i ; i=fa[i]) {
ma =-1;
dis[i]=0 ;
dfs_max(i,fa[i]);
if(ma>x) return 0;
}
} else {
for(int i=pos1 ; i!=fa[pos2] ; i=fa[i]) {
ma =-1;
dis[i]=0 ;
dfs_max(i,fa[i]);
if(ma>x) return 0;
}
}
return 1;
}
int main() {
ios::sync_with_stdio(false);
cin>>n>>s;
memset(head,-1,sizeof head);
for(int i=1 ; i<=n-1 ; i++) {
int u,v,w;
cin>>u>>v>>w;
add(u,v,w),add(v,u,w);
}
dfs(1,0);
dist[pos]=0,mi=0;
dfs(pos,0);
for(int i=pos ; i ; i=fa[i]) vis[i] = 1;
int l=0,r=2e9,ans;
while(l<=r) {
int mid = (l+r)>>1;
if(ok(mid)) r = mid-1,ans = mid;
else l = mid+1;
}
cout<<ans;
return 0;
}
/*
*/
Code_n:
int head[maxn],cnt;
struct node {
int u,v,w,next;
} e[maxn];
void add(int u,int v,int w) {
e[cnt].u=u,e[cnt].v=v,e[cnt].w=w;
e[cnt].next=head[u],head[u]=cnt++;
}
int n,dist[maxn],pos1,pos2,mi = -1,s,fa[maxn],ans = inf;
int vis[maxn];
void dfs1(int u,int p,int step) {
if(step>mi) pos1 = u,mi = step;
for(int i=head[u]; ~i; i=e[i].next) {
int v = e[i].v;
if(v==p) continue;
dfs1(v,u,step+e[i].w);
}
}
void dfs2(int u,int p) {
fa[u] = p;
if(dist[u]>mi) mi = dist[u],pos2=u;
for(int i=head[u]; ~i; i=e[i].next) {
int v = e[i].v;
if(v==p) continue;
dist[v] = dist[u]+e[i].w;
dfs2(v,u);
}
}
void dfs3(int u,int p) {
for(int i=head[u]; ~i; i=e[i].next) {
int v = e[i].v;
if(v==p||vis[v]) continue;
dist[v] = dist[u]+e[i].w;
dfs3(v,u);
}
}
int main() {
n=read(),mst(head,-1),s=read();
for(int i=1 ; i<n ; i++) {
int u,v,w;
u=read(),v=read(),w=read();
add(u,v,w),add(v,u,w);
}
dfs1(1,1,0),mi=-1;
dfs2(pos1,-1);
for(int i = pos2,j = pos2 ; ~i ; i = fa[i]) {
while(dist[i] - dist[j]<=s&&~j&&dist[i]-dist[j]>=0) {
int t = max(dist[j],dist[pos2] - dist[i]);
ans = min(ans,t);
j = fa[j];
}
}
if(dist[pos2]>s) {
out(ans);
return 0;
} else {
int ans = -1;
for(int i = pos2 ; ~i ; i = fa[i]) vis[i] = 1;
for(int i = pos2 ; ~i ; i = fa[i]) dist[i] =0, dfs3(i,fa[i]);
rep(i,1,n) ans = max(ans,dist[i]);
out(ans);
}
return 0;
}
/*
*/