bzoj1912(树的直径)
BZOJ1912」[Apio2010] patrol 巡逻
Description
Input
第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。
Output
输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。
Sample Input
8 1
1 2
3 1
3 4
5 3
7 5
8 5
5 6
1 2
3 1
3 4
5 3
7 5
8 5
5 6
Sample Output
11
HINT
10%的数据中,n ≤ 1000, K = 1;
30%的数据中,K = 1;
80%的数据中,每个村庄相邻的村庄数不超过 25;
90%的数据中,每个村庄相邻的村庄数不超过 150;
100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。
k=1直接求树的直径
k=2时把原来直径权值变为负值求直径,因为形成的两个环可能有重叠,取反后-(-1)变为+1
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int maxn=100000+10; const int nil=0x3f3f3f3f; struct my{ int v; int next; int w; }; my bian[maxn*2]; queue<int>Q; int ans; int p,fa=1,adj[maxn],d[maxn],pre[maxn],dp[maxn],vis[maxn],n,k;; void myinsert(int u,int v,int w){ bian[++fa].v=v; bian[fa].w=w; bian[fa].next=adj[u]; adj[u]=fa; } int bfs(int s){ memset(d,0x3f,sizeof(d)); Q.push(s); d[s]=0; pre[s]=0; while(!Q.empty()){ int u=Q.front();Q.pop(); for (int i=adj[u];i;i=bian[i].next){ int v=bian[i].v; if(d[v]==nil) { d[v]=d[u]+1; pre[v]=i; Q.push(v); } } } int x,y; for (x=y=1;x<=n;x++) if(d[x]>d[y]) y=x; return y; } int get(){ p=bfs(1); p=bfs(p); return d[p]; } int dfs(int x){ vis[x]=true; for (int i=adj[x];i;i=bian[i].next){ int v=bian[i].v; if(!vis[v]){ dfs(v); ans=max(ans,dp[x]+dp[v]+bian[i].w); dp[x]=max(dp[x],dp[v]+bian[i].w); } } return ans; } void change(){ for (;pre[p];p=bian[pre[p]^1].v) {//可以记录路径,但是一直没搞懂是怎么回事,可能是我太弱吧,记住好了 // printf("%d %d ",bian[pre[p]].v,bian[pre[p]^1].v); bian[pre[p]].w=bian[pre[p]^1].w=-1; } } int main(){ int u,v; scanf("%d%d",&n,&k); for (int i=1;i<n;i++){ scanf("%d%d",&u,&v); myinsert(u,v,1); myinsert(v,u,1); } int x=get(); if(k==1){ printf("%d\n",2*(n-1)-(x-1)); } else { change(); int y=dfs(1); printf("%d\n",2*n-x-y); } return 0; }