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

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 }
时间: 2024-10-14 09:44:02

bzoj 1912 巡逻(树直径)的相关文章

BZOJ 1912 巡逻(树直径)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1912 题意:给出一棵树,边权为1.现在加一条或两条边后,使得从1出发遍历每个点至少一次再回到1的路程最短. 思路:先求一次树的直径Max1.然后将直径的边权改为-1,再求一次直径Max2.答案为ans=(n-1)*2-(Max1-1)-(Max2-1). struct node { int u,v,w,next; }; node edges[N<<1]; int head[N],e;

(树直径) bzoj 1509

1509: [NOI2003]逃学的小孩 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 447  Solved: 240[Submit][Status][Discuss] Description Input 第一行是两个整数N(3 ? N ? 200000)和M,分别表示居住点总数和街道总数.以下M行,每行给出一条街道的信息.第i+1行包含整数Ui.Vi.Ti(1?Ui, Vi ? N,1 ? Ti ? 1000000000),表示街道i连接居住点U

BZOJ 3083 遥远的国度 树链剖分

3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 797  Solved: 181[Submit][Status] Description 描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀. 问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连

【BZOJ 1036】树的统计Count(树链剖分)

[BZOJ 1036]树的统计Count(树链剖分) 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 12991  Solved: 5233 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权

[HDOJ4612]Warm up(双连通分量,缩点,树直径)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 所有图论题都要往树上考虑 题意:给一张图,仅允许添加一条边,问能干掉的最多条桥有多少. 必须解决重边的问题,最后会说. 首先tarjan跑出所有的双连通分量和是桥的边还有桥的数量,这非常重要.接着缩点重新建图,然后两遍dfs找出两个在树上距离最远的点.我的想法就是把这条最长的链连成一个环,让它成为一个双连通分量,这样的效果是最好的.最后就是用桥的数量减去树直径再减一就得到了剩下的桥的数量了.求

(边双联通+树直径) hdu 4612

Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 4437    Accepted Submission(s): 1001 Problem Description N planets are connected by M bidirectional channels that allow instant transport

[HDOJ2196]Computer (树直径 树形DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2196 给一棵树,求树上各点到某点的距离中最长的距离.注意每个点都要求. 和普通求树的直径不一样,要求每一个点,点的数量是10000因此每一个点都跑一次dfs就会超时.因此先随便dfs一个点,找到一个点后以此点为原点再找距离它最远的点,再找一次即可找到树直径两端的点. 1 #include <algorithm> 2 #include <iostream> 3 #include <

BZOJ 2243 染色 | 树链剖分模板题进阶版

BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上还是原树上,把两个区间的信息合并的时候,要注意中间相邻两个颜色是否相同. 这代码好长啊啊啊啊 幸好一次过了不然我估计永远也De不出来 #include <cstdio> #include <cstring> #include <algorithm> using namesp

P3304 [SDOI2013]直径(【模板】树直径的必经边)

题目地址 基本思路: 题目要求树直径的必经边,那么首先应当获取一条直径. 获取直径后从直径上的两个端点分别遍历一次直径,每次遍历直径时从直径上的每个点分别dfs一次并不经过直径上的点,如果深度可以被替换则说明非必经边. #include<cstdio> #include<iostream> #include<queue> #include<cstring> #define ll long long using namespace std; const int