SP1825 【FTOUR2 - Free tour II】
\(SP1825\)
看到没有人用老师的办法,于是自己写一下思路
思路第一步:排除旧方法
首先这道题和\(4178\)不一样,因为那道题是计数,而这道题是求最值,最值有个坏处,就是对于来自相同子树的信息没法高效剔除,比如容斥用不了,举例来说,对于这道题,如果我们继续用尺取法维护黑点个数,对于一组刚好使\(cnt_l+cnt_r\leq k\)的\(l,r\),且\([l+1,r]\)所在子树都与\(l\)不同时就可以选取\(l~and~x\in [l+1,r]\),我们要使\(dis_l+dis_x\)只需使\(dis_x\)最大,因此每次递归建\(ST\)表\(RMQ\)即可
很奇怪的这道题这样做有\(50\)分
但\([l+1,r]\)所在子树有与\(l\)相同时至少我就束手无策了
于是我们放弃这个办法
思路第二步:放缩
我们依然不改变点分治本质思想,利用好经过根这个性质
如果不能尺取法贪心,那么\(DP\)可以吗,两个变量:过的黑点个数,和路径长度,我们想合并的根的不同儿子为根的子树
\(\therefore\)有\(f^{rt}\left[i\right][j](=l)\)表示以\(rt\)为根子树中,根到以\(i\)号儿子为根子树中一点路径上有\(j\)个黑点的路径最大长度
着眼在经过的黑点数不超过\(K\)个上,我们有可能会想到放缩,就是我们并不定义死刚好是\(j\)个黑点,好处等会儿就知道了
\(\therefore\)有\(f^{rt}\left[i\right][j](=l)\)表示以\(rt\)为根子树中,根到以\(i\)号儿子为根子树中一点路径上最多有\(j\)个黑点的路径最大长度
所求:\(Ans=\max\{f^{rt}[x][p],f^{rt}[y][q]\}(p+q+[color_{rt}="black"]\le k])\)
于是这里我们的定义就很好用了,那个\(\le\)号在实现中就可以取等
为了知道\(p,q\)的取值范围,我们再定义一个量\(cnt^{rt}_i\)表示以\(rt\)为根子树中,根到以\(i\)号儿子为根子树中一点最多经过的黑点数
\(\therefore p\le cnt^{rt}_x~~q\le cnt^{rt}_y\)
思路第三步:合并
如果我们这样做就要解决这个问题
如何求\(\max\{f^{rt}[x][p],f^{rt}[y][q]\}(p+q+[color_{rt}="black"]\le k])\)
有一个办法是暴力,因为对\(f^{rt}[x][p],f^{rt}[y][q]\)我们都可以\(O(n)\)求出
复杂度为\(O(\frac{n\cdot (n-1)}{2})=O(n^2)\)
但我们想并没有必要两两子树比较,由于求\(\max\)具有传递性,如果我们知道\(f^{rt}[s_1][p]>f^{rt}[s_2][p]\)我们就完全没有必要保留\(f^{rt}[s_2][p]\)了
因此我们想到合并
具体来说我们记录两个值,\(Now^{rt}_{(i,)x}\)/\(Past^{rt}_{(i,)x}\)分别表示以\(rt\)为根子树中,根到以\(i\)号儿子为根子树/以\(1\rightarrow i-1\)号儿子为根子树经过\(x\)个黑点的最长路径
但合并的顺序是个问题,每次我们需要比较求\(\max\)更新\(\max\{cnt_1,cnt_2...cnt_i\}\)次
由于答案与枚举儿子顺序无关,因此贪心可得对儿子按\(cnt_i\)从小到大排序即可
小结一下,对于这类最值点分治有一种办法是合并
代码常数大
#include<bits/stdc++.h>
#define re register
#define N 200005
#define INF 0x3f3f3f3f
using namespace std;
template<typename _int>
inline void read(re _int&x){
re _int res=0,flag=1;re char opt;
while((opt=getchar())>'9'||opt<'0')if(opt=='-')flag=-1;
while(opt>='0'&&opt<='9'){res=(res<<1)+(res<<3)+opt-'0';opt=getchar();}
x=res*flag;
}
struct Edge{
int to,next,v;
}e[N<<1];
int n,k,m,h[N],cnt,size[N],color[N],now[N],past[N],mind,ans=-INF;
char vis[N];
inline void AddEdge(re int x,re int y,re int z){e[++cnt]=(Edge){y,h[x],z};h[x]=cnt;}
struct Node{
int len,son,cnt;
inline char friend operator<(re Node a,re Node b){return a.cnt<b.cnt;}
}p[N<<1];
inline void dfs_size(re int x,re int prt){
re int i,y;
size[x]=1;
for(i=h[x];i;i=e[i].next){
y=e[i].to;if(y==prt||vis[y])continue;
dfs_size(y,x);
size[x]+=size[y];
}
}
inline void dfs_cnt(re int x,re int prt,re int pos,re int bcnt){
re int i,y;
bcnt+=color[x];
if(bcnt>k)return ;
if(bcnt>p[pos].cnt)p[pos].cnt=bcnt;
for(i=h[x];i;i=e[i].next){
y=e[i].to;if(y==prt||vis[y])continue;
dfs_cnt(y,x,pos,bcnt);
}
}
inline void dfs_dist(re int x,re int prt,re int dist,re int bcnt){
re int i,y;
bcnt+=color[x];
if(bcnt>k)return ;
if(dist>now[bcnt])now[bcnt]=dist;
for(i=h[x];i;i=e[i].next){
y=e[i].to;if(y==prt||vis[y])continue;
dfs_dist(y,x,dist+e[i].v,bcnt);
}
}
inline void Center(re int x,re int prt,re int&rt,re int root){
re int i,y,maxx=-INF;
for(i=h[x];i;i=e[i].next){
y=e[i].to;if(y==prt||vis[y])continue;
Center(y,x,rt,root);
maxx=max(maxx,size[y]);
}
maxx=max(maxx,size[root]-size[x]);
if(maxx<mind){mind=maxx;rt=x;}
}
inline void Solve(re int x){
re int i,j,y,rt,tot=0,tmp;mind=INF;
dfs_size(x,0);
Center(x,0,rt,x);
vis[rt]=1;
for(i=h[rt];i;i=e[i].next){
y=e[i].to;
p[++tot]=(Node){e[i].v,y,0};
dfs_cnt(y,0,tot,0);
}
sort(p+1,p+tot+1);
for(i=0;i<=p[tot].cnt;++i)past[i]=0;
for(i=1;i<=tot;++i){
y=p[i].son;
for(j=0;j<=p[i].cnt;++j)now[j]=-INF;
dfs_dist(y,0,p[i].len,0);
for(j=1;j<=p[i].cnt;++j)now[j]=max(now[j-1],now[j]);
for(j=0;j<=p[i].cnt;++j){
tmp=min(p[i-1].cnt,k-j-color[rt]);if(tmp<0)continue;
ans=max(ans,now[j]+past[tmp]);
}
for(j=0;j<=p[i].cnt;++j)past[j]=max(past[j],now[j]);
for(j=1;j<=p[i].cnt;++j)past[j]=max(past[j-1],past[j]);
}
for(i=h[rt];i;i=e[i].next){
y=e[i].to;
if(!vis[y])Solve(y);
}
}
inline void Read(void){
re int i,x,y,z;
read(n);read(k);read(m);
while(m--){read(x);color[x]=1;}
for(i=1;i<n;++i){read(x);read(y);read(z);AddEdge(x,y,z);AddEdge(y,x,z);}
}
int main(void){
Read();
Solve(1);
printf("%d\n",ans);
return 0;
}
SP1825 【FTOUR2 - Free tour II】的更多相关文章
- SP1825 FTOUR2 - Free tour II 点分治+启发式合并+未调完
题意翻译 给定一棵n个点的树,树上有m个黑点,求出一条路径,使得这条路径经过的黑点数小于等于k,且路径长度最大 Code: #include <bits/stdc++.h> using n ...
- SPOJ1825 FTOUR2 - Free tour II
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- SPOJ FTOUR2 - Free tour II
Description 有些黑点,问你选择不超过 \(k\) 个黑点的路径,路径权值最大是多少. Sol 点分治. 这是qzc的论文题,不过我感觉他的翻译好强啊...我还是选择了自己去看题目... 点 ...
- 【Pascal's Triangle II 】cpp
题目: Given an index k, return the kth row of the Pascal's triangle. For example, given k = 3,Return [ ...
- [spoj] FTOUR2 FREE TOUR II || 树分治
原题 给出一颗有n个点的树,其中有M个点是拥挤的,请选出一条最多包含k个拥挤的点的路径使得经过的权值和最大. 正常树分治,每次处理路径,更新答案. 计算每棵子树的deep(本题以经过拥挤节点个数作为d ...
- leetcode 【 Reverse Linked List II 】 python 实现
题目: Reverse a linked list from position m to n. Do it in-place and in one-pass. For example:Given 1- ...
- leetcode 【 Linked List Cycle II 】 python 实现
公司和学校事情比较多,隔了好几天没刷题,今天继续刷起来. 题目: Given a linked list, return the node where the cycle begins. If the ...
- 【Linked List Cycle II】cpp
题目: Given a linked list, return the node where the cycle begins. If there is no cycle, return null. ...
- 【Reverse Linked List II】cpp
题目: Reverse a linked list from position m to n. Do it in-place and in one-pass. For example:Given 1- ...
随机推荐
- Spring全家桶注解一览(精选)
废话 最近想整理一波Spring注解相关的文章,虽然写CURD就只涉及到那些常用的注解.但是笔者我也想去了解一下其他注解,丰富下自己的知识面(提升一下逼格!). 就想在网上搜了半天,好像大家的都差不多 ...
- Shell基础快速入门 了解shell运行原理
Shell简介 Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言. Shell 是指一种应用程序,这个应用程序提供了一个界 ...
- Create your first Java application
参考链接 -[IntelliJ IDEA] https://www.jetbrains.com/help/idea/creating-and-running-your-first-java-appli ...
- subprocess.popen.kill杀死所有子进程
一.使用subprocess模块 使用subprocess模块可创建子进程. subprocess. Popen ( args , bufsize=0 , executable=None , stdi ...
- JVM运行时内存结构学习
学习JVM运行模型比较重要,先看一幅图片: 运行时数据区(内存结构) : 1.方法区(Method Area)类的所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在这里定义.简单来说,所 ...
- Rediskey生命周期管理-key聚合
| 导语 Redis中的数据以k-v的方式组织:为了方便管理key一般具有某些特定的模式:有些key直接是由mysql中的表行数据转化而来:如果要对Redis的key进行生命周期管理,由于Redis的 ...
- Linux 系统中如何进入退出 vim 编辑器
在 Linux 中,vim 编辑器是系统自带的文本编辑器,但要修改某个文本文件,可不是像 Windows 那样操作,更有新手,进入 vi 编辑器后,无法退出以致于强制关机,其实,这个vim(vi)也是 ...
- js 简单的滑动4
js 简单的滑动教程(四) 作者:Lellansin 转载请标明出处,谢谢 在大概的了解滑动的基本原理和怎么去实现之后,现在我们将更深入的去讨论js的滑动. 相信细心的朋友应该已经发现了,在本教程 ...
- Dubbo -- 四种loadBalance负载均衡算法
Dubbo中的一个关键接口LoadBalance,dubbo是按照其中的规则来调用多台provider的服务的. 先看一下接口的实现类图: 从上图中我们可以看到dubbo提供了四种算法来实现负载均衡. ...
- 浅谈dubbo服务
Dubbo分布式服 推荐大家一个画图工具:https://www.processon.com/i/572d51efe4b0c3c74981ec14 1.Dubbo是一个分布式服务框架,致力于提供高性能 ...