题面

传送门

分析

显然,如果不加边,每条边都要走2次,总答案为2(n-1)

考虑k=1的朴素情况:

加一条边(a,b),这条边和树上a->b的路径形成一个环,这个环上的边只需要走一遍,所以答案会减少dist(a,b)-1 (a->b的路径少走一边,但是又多加了一条边,最终答案为2*(n-1)-dist(a,b)+1

显然dist(a,b)应该最大,求树上的直径\(L_1\)即可

接着推广到k=2的情况

加第二条边时,又会形成一个环,这个环和第一条边形成的环可能有重叠,重叠部分要走两遍,答案又会增加

因此,我们把直径上的边权取反(1变为-1),在直径取反后的树上再次求直径,设直径为\(L_2\)

答案就是\(2(n-1)-(L_1-1)-(L_2-1)\)

注意两次BFS求直径的方法在负权图上求直径不成立,需要用树形DP

具体方法如下:

1.在原图上用两次BFS求出直径\(L_1\)端点a,b

2.通过LCA和树上差分将直径上的边标记,并取反边权

3.用树形DP求出新直径\(L_2\)

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#define maxlog 32
#define maxn 400005
#define INF 0x7fffffff
using namespace std;
int n,k;
struct edge {
int from;
int to;
int next;
int len;
} E[maxn*2];
int sz=1;
int head[maxn];
void add_edge(int u,int v,int w) {
sz++;
E[sz].from=u;
E[sz].to=v;
E[sz].len=w;
E[sz].next=head[u];
head[u]=sz;
} namespace k_1 {
struct node {
int x;
int t;
node() { }
node(int u,int dis) {
x=u;
t=dis;
}
};
int vis[maxn];
node bfs(int s) {
node now,ans;
queue<node>q;
q.push(node(s,0));
memset(vis,0,sizeof(vis));
ans.t=-INF;
while(!q.empty()) {
now=q.front();
q.pop();
int x=now.x;
vis[x]=1;
if(now.t>ans.t) {
ans.t=now.t;
ans.x=now.x;
}
for(int i=head[x]; i; i=E[i].next) {
int y=E[i].to;
if(!vis[y]) {
q.push(node(y,now.t+1));
}
}
}
return ans;
} void solve() {
node p=bfs(1);
node q=bfs(p.x);
printf("%d\n",2*(n-1)-q.t+1);
}
} namespace k_2 {
int log2n;
struct node {
int x;
int t;
node() { }
node(int u,int dis) {
x=u;
t=dis;
}
};
int vis[maxn];
int mark[maxn]; node bfs(int s,int tim) {
node now,ans;
queue<node>q;
q.push(node(s,0));
memset(vis,0,sizeof(vis));
ans.t=-INF;
ans.x=s;
if(n==1) return node(1,0);
while(!q.empty()) {
now=q.front();
q.pop();
int x=now.x;
vis[x]=1;
if(tim==1) {
if(now.t>=ans.t&&now.x!=s) {
ans.t=now.t;
ans.x=now.x;
}
}else{
if(now.t>=ans.t) {
ans.t=now.t;
ans.x=now.x;
}
}
for(int i=head[x]; i; i=E[i].next) {
int y=E[i].to;
if(!vis[y]) {
q.push(node(y,now.t+E[i].len));
}
}
}
return ans;
} int anc[maxn][maxlog];
int deep[maxn];
void dfs1(int x,int fa) {
deep[x]=deep[fa]+1;
anc[x][0]=fa;
for(int i=1; i<=log2n; i++) {
anc[x][i]=anc[anc[x][i-1]][i-1];
}
for(int i=head[x]; i; i=E[i].next) {
int y=E[i].to;
if(y!=fa) {
dfs1(y,x);
}
}
} void dfs2(int x,int fa) {
for(int i=head[x]; i; i=E[i].next) {
int y=E[i].to;
if(y!=fa) {
dfs2(y,x);
mark[x]+=mark[y];
}
}
} int lca(int x,int y) {
if(deep[x]<deep[y]) swap(x,y);
for(int i=log2n; i>=0; i--) {
if(deep[anc[x][i]]>=deep[y]) x=anc[x][i];
}
if(x==y) return x;
for(int i=log2n; i>=0; i--) {
if(anc[x][i]!=anc[y][i]) {
x=anc[x][i];
y=anc[y][i];
}
}
return anc[x][0];
} int len=0;
int d[maxn];
void dp(int x,int fa){
d[x]=0;
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(y!=fa){
dp(y,x);
len=max(len,d[x]+d[y]+E[i].len);
d[x]=max(d[x],d[y]+E[i].len);
}
}
} void solve() {
int u,v;
int ans=2*(n-1);
log2n=log2(n)+1;
dfs1(1,0);
node p=bfs(1,1);
node q=bfs(p.x,2);
ans=ans-q.t+1; memset(mark,0,sizeof(mark));
mark[p.x]++;
mark[q.x]++;
mark[lca(p.x,q.x)]-=2;
dfs2(1,0); memset(head,0,sizeof(head));
memset(E,0,sizeof(E));
sz=1;
for(int i=2; i<=n; i++) {
add_edge(i,anc[i][0],mark[i]==1?-1:1);
add_edge(anc[i][0],i,mark[i]==1?-1:1);
} memset(d,-0x3f,sizeof(d));
dp(1,0);
ans=ans-len+1; printf("%d\n",ans);
}
}
int main() {
int u,v;
scanf("%d %d",&n,&k);
sz=1;
for(int i=1; i<n; i++) {
scanf("%d %d",&u,&v);
add_edge(u,v,1);
add_edge(v,u,1);
}
if(k==1) k_1::solve();
else k_2::solve();
}

BZOJ 1912(树的直径+LCA)的更多相关文章

  1. 【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树的直径/LCA/树的点分治

    题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F ...

  2. BZOJ 2282 & 树的直径

    SDOI2011的Dayx第2题 题意: 在树中找到一条权值和不超过S的链(为什么是链呢,因为题目中提到“使得路径的两端都是城市”,如果不是链那不就不止两端了吗——怎么这么机智的感觉...),使得不在 ...

  3. BZOJ 1912: [Apio2010]patrol 巡逻 (树的直径)(详解)

    题目: https://www.lydsy.com/JudgeOnline/problem.php?id=1912 题解: 首先,显然当不加边的时候,遍历一棵树每条边都要经过两次.那么现在考虑k==1 ...

  4. bzoj 1912 巡逻(树直径)

    Description Input 第一行包含两个整数 n, K(1 ≤ K ≤ 2).接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n). Ou ...

  5. 【BZOJ】1912: [Apio2010]patrol 巡逻(树的直径)

    题目 传送门:QWQ 分析 $ k=1 $ 时显然就是树的直径 $ k=2 $ 时怎么做呢? 做法是把一开始树的直径上的边的边权改成$ -1 $,那么当我们第二次用这些边做环时就抵消了一开始的贡献. ...

  6. 51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径

    51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径 题面 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即 ...

  7. bzoj 1776: [Usaco2010 Hol]cowpol 奶牛政坛——树的直径

    农夫约翰的奶牛住在N (2 <= N <= 200,000)片不同的草地上,标号为1到N.恰好有N-1条单位长度的双向道路,用各种各样的方法连接这些草地.而且从每片草地出发都可以抵达其他所 ...

  8. XTU1267:Highway(LCA+树的直径)

    传送门 题意 有n个小镇,Bobo想要建造n-1条边,并且如果在u到v建边,那么花费是u到v的最短路长度(原图),问你最大的花费. 分析 比赛的时候没做出来,QAQ 我们首先要找到树的直径起点和终点, ...

  9. [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)

    [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...

随机推荐

  1. web开发中SESSION的本质

    有一点我们必须承认,大多数web应用程序都离不开session的使用.这篇文章将会结合php以及http协议来分析如何建立一个安全的会话管理机制.我们先简单的了解一些http的知识,从而理解该协议的无 ...

  2. Linux 实操(root密码重置 无法上网 安装xrdp)

    一个是显示器显示不咋地,一个是想远程连接Linux,这样就可以放到下面机房去了.所以想安装一个远程桌面链接.从网上搜了搜,好多.安装的时候需要root权限,但是密码忘了.好吧,开始捣鼓root密码 按 ...

  3. java 关键字volatile

    一.Java内存模型 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的. Java内存模型规定了所有的变量都存储在主内存中.每条线程中还有自己的工作内存,线程的工作 ...

  4. TreeMap和Comparable接口

    备注:HashMap线程不安全,效率高,允许key.value为空 HasTable线程安全.效率低.不允许key或value为空 TreeMap在存储时会自动调用comparable方法进行排序,当 ...

  5. MAN VGEXTEND

    VGEXTEND(8)                                                        VGEXTEND(8) NAME/名称       vgexten ...

  6. 【leetcode】1047. Remove All Adjacent Duplicates In String

    题目如下: Given a string S of lowercase letters, a duplicate removal consists of choosing two adjacent a ...

  7. EditText控件常用属性

    常用属性 android:id——控件ID android:layout_width——控件宽度 android:layout_height——控件高度 android:text——文本内容 andr ...

  8. yum源更换

    折腾了半天,怀疑自己能力 的时候,发现原来不是我的错.树莓派换源国内的aliyun,163都不能用,最好找到这个 # CentOS-Base.repo # # The mirror system us ...

  9. Cluster基础(二):ipvsadm命令用法、部署LVS-NAT集群、部署LVS-DR集群

    一.ipvsadm命令用法 目标: 准备一台Linux服务器,安装ipvsadm软件包,练习使用ipvsadm命令,实现如下功能: 使用命令添加基于TCP一些的集群服务 在集群中添加若干台后端真实服务 ...

  10. Hadoop学习之路(二)HDFS基础

    1.HDFS前言 HDFS:Hadoop Distributed File System,Hadoop分布式文件系统,主要用来解决海量数据的存储问题. 设计思想 分散均匀存储 dfs.blocksiz ...