bzoj 1912 tree_dp
这道题我们加一条路可以减少的代价为这条路两端点到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的更多相关文章
- BZOJ 1912: [Apio2010]patrol 巡逻 (树的直径)(详解)
题目: https://www.lydsy.com/JudgeOnline/problem.php?id=1912 题解: 首先,显然当不加边的时候,遍历一棵树每条边都要经过两次.那么现在考虑k==1 ...
- [BZOJ 1912] patrol 巡逻
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1912 Algorithm: K=0:res=(n-1)*2 每条边恰好走2遍 K=1 ...
- BZOJ 1912:[Apio2010]patrol 巡逻(树直径)
1912: [Apio2010]patrol 巡逻 Input 第一行包含两个整数 n, K(1 ≤ K ≤ 2).接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ ...
- BZOJ 1912 巡逻
重赋边权. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm& ...
- bzoj 1912 巡逻(树直径)
Description Input 第一行包含两个整数 n, K(1 ≤ K ≤ 2).接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n). Ou ...
- bzoj 1912 : [Apio2010]patrol 巡逻 树的直径
题目链接 如果k==1, 显然就是直径. k==2的时候, 把直径的边权变为-1, 然后在求一次直径. 变为-1是因为如果在走一次这条边, 答案会增加1. 学到了新的求直径的方法... #includ ...
- BZOJ 1912 巡逻(算竞进阶习题)
树的直径 这题如果k=1很简单,就是在树的最长链上加个环,这样就最大化的减少重复的路程 但是k=2的时候需要考虑两个环的重叠部分,如果没有重叠部分,则和k=1的情况是一样的,但是假如有重叠部分,我们可 ...
- 题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)
本来抄了篇题解,后来觉得题解都太不友好(我太菜了),一气之下自己打...一打打到第二天QAQ 首先什么边也不加时,总路程就是2*(n-1) 考虑k=1的时候,答案显然是2*(n-1)-直径+1=2*n ...
- bzoj 1912: [Apio2010]patrol 巡逻【不是dp是枚举+堆】
我是智障系列.用了及其麻烦的方法= =其实树形sp就能解决 设直径长度+1为len(环长) 首先k=1,直接连直径两端就好,答案是2*n-len 然后对于k=2,正常人的做法是树形dp:先求直径,然后 ...
随机推荐
- 在 Range 对象中,Min (14)必须小于或等于 max (-1)。
DataTable dt = ds.Tables[]; DataRow[] drs = dt.Select("Id=" + categoryID ); 解决方法:将参数用单引号阔起 ...
- AMH面板命令操作大全
LNMP面板 - AMH 命令使用nginx篇 » SSH Nginx1) 有步骤提示操作: ssh执行命令: amh nginx然后选择对应选项进行操作. 2) 或直接操作: 启动Nginx: am ...
- HASH表的实现(拉链法)
本文的一些基本概念参考了一部分百度百科,当然只保留了最有价值的部分,代码部分完全是自己实现! 简介 哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据 ...
- overflow:scroll 滚动条不显示
overflow:scroll 滚动条不显示 ::-webkit-scrollbar-thumb 可能因为 自定义的滚动条height比元素可展示内容大
- poj 1719 Shooting Contest (二分匹配)
Shooting Contest Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 3812 Accepted: 1389 ...
- BZOJ 1342: [Baltic2007]Sound静音问题 | 单调队列维护的好题
题目: 给n个数字,一段合法区间[l,l+m-1]要求max-min<=c 输出所有合法区间的左端点,如果没有输出NONE 题解: 单调队列同时维护最大值和最小值 #include<cst ...
- UVA.10986 Fractions Again (经典暴力)
UVA.10986 Fractions Again (经典暴力) 题意分析 同样只枚举1个,根据条件算出另外一个. 代码总览 #include <iostream> #include &l ...
- HDOJ(HDU).2191. 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (DP 多重背包+二进制优化)
HDOJ(HDU).2191. 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (DP 多重背包+二进制优化) 题意分析 首先C表示测试数据的组数,然后给出经费的金额和大米的种类.接着是每袋大米的 ...
- angularJS批量删除 品优购删除品牌(通用复选框批量选中删除解决思路)
思路: 一步:在点击复选框时维护变量数组 在js中定义一个数组变量, 给复选框添加点击动作, 在动作中判断当前复选框是否为选中状态(即点击后复选框的是否选中状态), 若为选中状态,则向数组中添加选中的 ...
- [技巧篇]00.TrimFilter去掉jsp页面空白,提升访问速度
最近感觉项目访问的速度有点慢,我就在网络中一顿搜索,发下了一个好东东,忍不住跟大家分享,希望大家可以试一试,确实有提升的空间啊!要求去除空白区.提取公用代码.减小页面. 胖先生乱搜之下,找到了Trim ...