随时会更新
P4408
根据题意可以发现构成的图是一棵树。
然后可以发现行走路径是从 C 到距离较近的 A 或 B 点,再走完 A-B 路径,所以对于 A-B 路径,其长度与 C 的位置是无关的,所以他有一个固定的上限,在根据树的直径的性质,可以将其 A-B 确定为树的直径,之后我们要做的就是处理出直径一端点 A 与所有点的距离,另一端点 B 与所有点的距离,枚举一遍 n 更新答案即可。
时间复杂度 (O(n)) 。
#include <cstdio>
#include <algorithm>
#define int long long
const int N=400070;
struct Tree{ int to,nxt,w; }e[N];
int n,m,cnt,maxdis,maxu,A,B;
int head[N],d[2][N];
void dfs(int u,int fa,int dis){
if(dis>maxdis) maxdis=dis,maxu=u;
for(int i=head[u],v;i;i=e[i].nxt){
v=e[i].to;if(v==fa) continue;
dfs(v,u,dis+e[i].w);
}
}
void DFS(int u,int fa,int k){
for(int i=head[u],v;i;i=e[i].nxt){
v=e[i].to;if(v==fa) continue;
d[k][v]=d[k][u]+e[i].w;
DFS(v,u,k);
}
}
void add(int from,int to,int val){e[++cnt].to=to,e[cnt].w=val,e[cnt].nxt=head[from],head[from]=cnt;}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1,u,v,w;i<=m;++i){
scanf("%lld%lld%lld",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
dfs(1,0,0),maxdis=0,A=maxu,dfs(A,0,0),B=maxu,DFS(A,0,0),DFS(B,0,1);
int ans=0;
for(int i=1;i<=n;++i)
ans=std::max(ans,maxdis+std::min(d[0][i],d[1][i]));
printf("%lld
",ans);
}
P3639
(k = 0) 时,因为要回到最终的起点,根据树的性质,我们可以迅速地得到答案为 (2*(n-1)) 。
(k = 1) 时,这条添加的边必须要遍历一遍,根据树的性质,添加一条边后树上肯定形成了一个环,所以整个环只需要遍历一遍,那我们要是减少的代价最多,根据树的性质,我们就需要找到树的直径,将两端相连,记直径的长度为 L1,
这样我们此时的答案是 (2*(n-1)-L1+1) 。
(k = 2) 时,根据之前的性质,我们原来的图中出现了两个环,若两个环没有重合的部分,那么我们的结论可以类比上题,但如果有重合的部分,此时我们肯定需要将重合的部分给去除掉,为了做到这一点,要做的就是将第一遍遍历得到的直径上所有边权改为 -1,再在新图上找一条新的直径,记直径的长度为 L2,很显然,答案是 (2*(n-1)-L1+1-L2+1) 。
#include <cstdio>
#include <algorithm>
#include <map>
const int N=200070;
const int inf=1e9;
struct Tree{ int to,nxt; }e[N];
bool vis[N];
std::map<int,int>mp[N];
int n,k,cnt,maxdis,maxu,L1,L2;
int head[N],f[N],pre[N],d[N];
void add(int from,int to){e[++cnt].to=to,e[cnt].nxt=head[from],head[from]=cnt;}
void dfs(int u,int fa,int dis){
if(dis>maxdis) maxdis=dis,maxu=u;
for(int i=head[u],v;i;i=e[i].nxt){
v=e[i].to;if(v==fa) continue;
dfs(v,u,dis+1);
}
}
void dfs2(int u,int fa,int dis){
if(dis>maxdis) maxdis=dis,maxu=u;
pre[u]=fa;
for(int i=head[u],v;i;i=e[i].nxt){
v=e[i].to;if(v==fa) continue;
dfs2(v,u,dis+1);
}
}
int get(){
dfs(1,0,0),maxdis=0,dfs2(maxu,0,0);
return maxdis;
}
void modify(int u){
if(!u) return;
mp[u][pre[u]]=mp[pre[u]][u]=-1;
modify(pre[u]);
}
void dp(int u){
vis[u]=1;
for(int i=head[u],v;i;i=e[i].nxt){
v=e[i].to;if(vis[v]) continue;
dp(v),L2=std::max(L2,f[v]+f[u]+mp[u][v]),f[u]=std::max(f[u],f[v]+mp[u][v]);
}
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1,u,v;i<n;++i){
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
mp[u][v]=mp[v][u]=1;
}
L1=get();
if(k==1){
printf("%d
",2*(n-1)-L1+1);
return 0;
}
modify(maxu),dp(1);
printf("%d
",2*n-L1-L2);
}