这道题我们加一条路可以减少的代价为这条路两端点到lca的路径的长度,相当于一条链,那么如果加了两条链的话,这两条链重复的部分还是要走两遍,反而对答案没有了贡献(其实这个可以由任意两条链都可以看成两条不重叠的链来证明),那么这道题k=2的时候就转化为了求出树上两条链,使得两条链不重叠的长度最大,那么答案就是(n-1)<<1-SumLen+2.当k=1的时候我们直接求出来树的最长链然后减去就好了,这个在此不再赘述。

  对于树上两链不重复部分最大我们是可以tree_dp的,设w[i][0..4]来表示当前以i为根的子树中选取了0/1/2条链的最大值,同时我们保留了一个3,4来记录以i为一端点的最长链,同时选取了0/1条最长链的最大值,这样直接转移就好了。

  我写的是另外一种方法,先找出最长链,然后将最长链上的边长设为-1,然后再找一次最长链,这样求出来的就是答案。

  反思:开始没意识到第二次最长链不能用两边bfs,所以果断的写了bfs,后来才发现的,又临时加了一个tree_dp,因为加的路必须选,所以我们要将每个点的最长和次长链设为-inf,叶子节点的为0,然后用非叶子节点更新答案,然后竟然1A,真是感动= =。

/**************************************************************
    Problem: 1912
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:1268 ms
    Memory:5884 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 100010
#define maxm 200020
#define inf (~0U>>1)
 
using namespace std;
 
int n,k,l;
int pre[maxm],other[maxm],last[maxn],len[maxm];
int que[maxn],dis[maxn],father[maxn],flag[maxn],max_1[maxn],max_2[maxn];
 
void connect(int x,int y) {
    pre[++l]=last[x];
    last[x]=l;
    other[l]=y;
    len[l]=;
}
 
void bfs(int x) {
    memset(que,,sizeof que);
    memset(dis,,sizeof dis);
    memset(father,,sizeof father);
    memset(flag,,sizeof flag);
    int h=,t=;
    que[]=x; dis[x]=; flag[x]=;
    while (h<t) {
        int cur=que[++h];
        for (int p=last[cur];p;p=pre[p]) {
            if (flag[other[p]]) continue;
            father[other[p]]=p;
            dis[other[p]]=dis[cur]+len[p];
            flag[other[p]]=;
            que[++t]=other[p];
        }
    }
}
 
int tree_dp() {
    int ans=-inf;
    memset(que,,sizeof que);
    memset(flag,,sizeof flag);
    memset(dis,,sizeof dis);
    memset(max_1,-,sizeof max_1);
    memset(max_2,-,sizeof max_2);
    int h=,t=;
    que[]=; flag[]=; dis[]=;
    while (h<t) {
        int cur=que[++h];
        for (int p=last[cur];p;p=pre[p]) {
            if (flag[other[p]]) continue;
            que[++t]=other[p]; flag[other[p]]=; dis[other[p]]=dis[cur]+;
        }
    }
    //for (int i=1;i<=n;i++) printf("%d ",que[i]); printf("\n");
    for (int i=n;i;i--) {
        int cur=que[i];
        for (int p=last[cur];p;p=pre[p]) {
            if (dis[other[p]]<dis[cur]) continue;
            if (max_1[other[p]]+len[p]>max_1[cur])
                max_2[cur]=max_1[cur],max_1[cur]=max_1[other[p]]+len[p]; else
            if (max_1[other[p]]+len[p]>max_2[cur])
                max_2[cur]=max_1[other[p]]+len[p];
        }
        if (max_1[cur]<-) max_1[cur]=max_2[cur]=; else ans=max(ans,max(max_1[cur]+max_2[cur],max_1[cur]));
    }
    //for (int i=1;i<=n;i++) printf("|%d %d\n",max_1[i],max_2[i]);
    return ans;
}
 
int getmax() {
    int s=;
    for (int i=;i<=n;i++) if (dis[i]>dis[s]) s=i;
    return s;
}
 
int main() {
    scanf("%d%d",&n,&k); l=;
    for (int i=;i<n;i++) {
        int x,y; scanf("%d%d",&x,&y);
        connect(x,y); connect(y,x);
    }
    bfs(); bfs(getmax());
    if (k==) {
        printf("%d\n",*n-dis[getmax()]);
        return ;
    }
    int cur=getmax(),ans=dis[cur]-;
    while (father[cur]) len[father[cur]]=len[father[cur]^]=-,cur=other[father[cur]^];
    ans+=tree_dp()-;
    printf("%d\n",*n--ans);
    return ;
}

bzoj 1912 tree_dp的更多相关文章

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

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

  2. [BZOJ 1912] patrol 巡逻

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1912 Algorithm: K=0:res=(n-1)*2   每条边恰好走2遍 K=1 ...

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

    1912: [Apio2010]patrol 巡逻 Input 第一行包含两个整数 n, K(1 ≤ K ≤ 2).接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ ...

  4. BZOJ 1912 巡逻

    重赋边权. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm& ...

  5. bzoj 1912 巡逻(树直径)

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

  6. bzoj 1912 : [Apio2010]patrol 巡逻 树的直径

    题目链接 如果k==1, 显然就是直径. k==2的时候, 把直径的边权变为-1, 然后在求一次直径. 变为-1是因为如果在走一次这条边, 答案会增加1. 学到了新的求直径的方法... #includ ...

  7. BZOJ 1912 巡逻(算竞进阶习题)

    树的直径 这题如果k=1很简单,就是在树的最长链上加个环,这样就最大化的减少重复的路程 但是k=2的时候需要考虑两个环的重叠部分,如果没有重叠部分,则和k=1的情况是一样的,但是假如有重叠部分,我们可 ...

  8. 题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)

    本来抄了篇题解,后来觉得题解都太不友好(我太菜了),一气之下自己打...一打打到第二天QAQ 首先什么边也不加时,总路程就是2*(n-1) 考虑k=1的时候,答案显然是2*(n-1)-直径+1=2*n ...

  9. bzoj 1912: [Apio2010]patrol 巡逻【不是dp是枚举+堆】

    我是智障系列.用了及其麻烦的方法= =其实树形sp就能解决 设直径长度+1为len(环长) 首先k=1,直接连直径两端就好,答案是2*n-len 然后对于k=2,正常人的做法是树形dp:先求直径,然后 ...

随机推荐

  1. ajax与servlet交互(通过JSON),JAVA的arraylist传到前端的方法

    所实现的效果:首先从前端(ajax)传参数给servlet,然后servlet经过处理,把arraylist类型的参数以JSON字符串的形式返回给前端(ajax),然后前端经过解析,把JSON字符串解 ...

  2. 腾讯云 activeMQ Illegal character in hostname at index 7

    查找问题步骤: 1.  /usr/local/apache-activemq-5.9.1/data/activemq.log 看一下这个.log后缀的启动日志,可以将它下载下来再看. 先尝试修改配置文 ...

  3. python爬虫--打开爬取页面

    def requests_view(response): import webbrowser requests_url = response.url base_url = '<head>& ...

  4. 第一章 持续集成jenkins工具使用之部署

    1.1 硬件要求 内存:至少512MB 磁盘空间:10G JDK8 最好同时安装jre 从官网https://jenkins.io/download/下载最新的war包(Generic Java Pa ...

  5. CSS设计指南之一 HTML标记与文档结构

    HTML标记与文档结构 之所以从HTML讲起,是因为CSS的用途就是为HTML标记添加样式. 1.1 HTML标记基础 对于每个包含内容的元素,根据它所包含的内容是不是文本,有两种不同的方式给它们加标 ...

  6. BZOJ 2460 元素(贪心+线性基)

    显然线性基可以满足题目中给出的条件.关键是如何使得魔力最大. 贪心策略是按魔力排序,将编号依次加入线性基,一个数如果和之前的一些数异或和为0就跳过他. 因为如果要把这个数放进去,那就要把之前的某个数拿 ...

  7. 转:使用 python Matplotlib 库 绘图 及 相关问题

     使用 python Matplotlib 库绘图      转:http://blog.csdn.net/daniel_ustc/article/details/9714163 Matplotlib ...

  8. [APIO2017]商旅 0/1分数规划

    ---题面--- 题解: upd: 在洛谷上被Hack了...思路应该是对的,代码就别看了 感觉有个地方还是非常妙的,就是因为在x买东西,在y卖出,就相当于直接从x走向了y,因为经过中间的城市反正也不 ...

  9. Android 职业路上--只要还有一丝希望,不到最后一刻,不要轻言放弃--从屌丝到进入名企

    写在前面:只要还有一丝希望,不到最后一刻,不要轻言放弃! 来到西安十来天了,现在基本安顿下来了,这几天在工作中也遇到一些技术问题,但都没来得及总结分享,现在想和大家分享一下我的工作求职经历! 接触an ...

  10. 【BZOJ3240】【NOI2013】矩阵游戏(数论)

    [BZOJ3240][NOI2013]矩阵游戏(数论) 题面 BZOJ 题解 搞什么矩阵十进制快速幂加卡常? 直接数学推导不好吗? 首先观察如何从每一行的第一个推到最后一个 \(f[i]=a·f[i- ...