bzoj 1912 巡逻(树直径)
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的数据,yy一下就可以发现要找树的直径,然而对于k=2的点,相当于找两条直径,但是会发现,如果这两条直径重复了会很蛋疼,还是会重复走到,因此我们找完第一个直径后,直径上面的边全部赋值为-1,然后再找第二条直径。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 int tot,go[200005],first[100005],next[200005]; 7 int op[200005]; 8 int vis[100005],dis[100005],c[200005],from[100005],pre[100005]; 9 int d[100005],n,k,ans,Mx2,val[200005]; 10 void insert(int x,int y,int z){ 11 tot++; 12 go[tot]=y; 13 next[tot]=first[x]; 14 first[x]=tot; 15 val[tot]=z; 16 } 17 void add(int x,int y,int z){ 18 insert(x,y,z);op[tot]=tot+1; 19 insert(y,x,z);op[tot]=tot-1; 20 } 21 void bfs(int x){ 22 int h=0,t=1; 23 for (int i=1;i<=n;i++) pre[i]=from[i]=0; 24 for (int i=1;i<=n;i++) vis[i]=0,dis[i]=0; 25 c[1]=x;vis[x]=1;dis[x]=0; 26 while (h<=t){ 27 h++; 28 for (int i=first[c[h]];i;i=next[i]){ 29 int pur=go[i]; 30 if (vis[pur]) continue; 31 pre[pur]=c[h]; 32 from[pur]=i; 33 vis[pur]=1;c[++t]=pur;dis[pur]=dis[c[h]]+val[i]; 34 } 35 } 36 } 37 void pianfen1(){ 38 bfs(1); 39 int mx=1; 40 for (int i=2;i<=n;i++) if (dis[i]>dis[mx]) mx=i; 41 bfs(mx); 42 Mx2=1; 43 for (int i=2;i<=n;i++) if (dis[Mx2]<dis[i]) Mx2=i; 44 if (k==1) printf("%d\n",2*(n-1)-dis[Mx2]+1); 45 } 46 void dfs(int x){ 47 d[x]=0,vis[x]=1;int mx1=0,mx2=0; 48 for (int i=first[x];i;i=next[i]){ 49 int pur=go[i]; 50 if (vis[pur]) continue; 51 dfs(pur); 52 if (d[pur]+val[i]>mx1) mx2=mx1,mx1=d[pur]+val[i]; 53 else 54 if (d[pur]+val[i]>mx2) mx2=d[pur]+val[i]; 55 } 56 if (mx1+mx2>ans) ans=mx1+mx2; 57 d[x]=mx1; 58 } 59 int main(){ 60 scanf("%d%d",&n,&k); 61 for (int i=1;i<n;i++){ 62 int x,y; 63 scanf("%d%d",&x,&y); 64 add(x,y,1); 65 } 66 pianfen1(); 67 int cnt=2*(n-1)-dis[Mx2]+1; 68 if (k==1) return 0; 69 for (int i=1;i<=n;i++) vis[i]=0,d[i]=0x3f3f3f3f; 70 for (int i=Mx2;i!=0;i=pre[i]) val[from[i]]=-1,val[op[from[i]]]=-1; 71 ans=0; 72 dfs(1); 73 74 printf("%d\n",cnt-ans+1); 75 }