Description
Input
第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。
Output
输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。
Range
10%的数据中,n ≤ 1000, K = 1;
30%的数据中,K = 1;
80%的数据中,每个村庄相邻的村庄数不超过 25;
90%的数据中,每个村庄相邻的村庄数不超过 150;
100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。
30%的数据中,K = 1;
80%的数据中,每个村庄相邻的村庄数不超过 25;
90%的数据中,每个村庄相邻的村庄数不超过 150;
100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。
Solution
对于k=1的情况,直接求树的直径即可。
对于k=2的情况,在求完一遍直径之后,要把直径上所有的边权改为 -1,然后求直径即可。
upd:有负权边情况下,两次bfs/dfs不能求树的直径,只能用 dp 求
Code
// By YoungNeal #include<queue> #include<cstdio> #include<cstring> #include<iostream> #define N 100005 using namespace std; bool vis[N]; ,tot; int pre[N],d[N],head[N]; struct Edge{ int to,nxt,dis; }edge[N<<]; void add(int x,int y){ edge[++cnt].to=y; edge[cnt].nxt=head[x]; edge[cnt].dis=; head[x]=cnt; } int bfs(int now){ queue<int> q; memset(d,0x3f,sizeof d); pre[now]=,d[now]=; q.push(now); while(q.size()){ int u=q.front();q.pop(); for(int i=head[u];i;i=edge[i].nxt){ int to=edge[i].to; if(d[to]!=0x3f3f3f3f) continue; pre[to]=i; d[to]=d[u]+; q.push(to); } } ; ;x<=n;x++) if(d[x]>d[t]) t=x; return t; } int work(){ p=bfs(); p=bfs(p); return d[p]; } void update(){ ].to) edge[pre[p]].dis=edge[pre[p]^].dis=-; } void dp(int now){ vis[now]=; for(int i=head[now];i;i=edge[i].nxt){ int to=edge[i].to; if(vis[to]) continue; dp(to); tot=max(tot,d[now]+d[to]+edge[i].dis); d[now]=max(d[now],d[to]+edge[i].dis); } } signed main(){ scanf("%d%d",&n,&m); ;i<n;i++){ scanf("%d%d",&x,&y); add(x,y);add(y,x); } int ans=work(); ){ printf(*(n-)-ans+); ; } update(); memset(d,,sizeof d); dp(); printf(*(n-)-ans+-tot+); }