http://www.spoj.com/problems/FTOUR2/en/

题目大意:给一棵黑白染色的树,求边权和最大且经过黑点不超过K的路径。

————————————————————

前排膜拜hzwer,借(抄)鉴(袭)了神犇的代码与思路,要看简洁的思路的话:http://hzwer.com/5984.html

然而……就算是抄了代码,还是没懂这题怎么做怎么办?

别着急,这道神神神题慢慢来。

——————————————————————

首先判断我们要放什么板子,很显然我们想到的是和树有关的算法,全拎出来一遍发现点分治貌似可行?

那我们点分治就直接求就好了!

e然后跟着下面的代码慢慢剖析(与程序有些不符):

1.calcg函数:和普通板子一样,是找重心的。

2.getmaxp函数:处理子树,返回当前子树节点到子树根的路径中最多黑点个数,同时我们主要完成下面数组的更新:

  1.nump[i]:统计i到根节点的路径上的黑点数。

  2.dis[i]:统计i到根节点的路径权值和。

3.getmaxt函数:处理子树的t数组,其中t数组含义如下:

  t[i]:当前子树节点到子树根且经过至多i个黑点的路径的最大权值和。

4.solve函数:处理答案ans,过程如下:

  1.calcg得到重心作为根节点。

  2.getmaxp每个子树的根节点,并且放入我们准备好的s数组里(同时存入子树的根,用make_pair函数更加便捷)。

  3.sort s数组。//原因见4.4

  4.遍历s数组:

    0.初始化t数组//请将该操作放在下面和循环一起进行,不然会卡常数导致TLE

    1.getmaxt子树根。

    2.处理maxn数组,并且更新ans,maxn数组含义如下:

      maxn[i]:以根节点为起点,终点在前面已经搜过的子树中,且该路径至多经过i个黑点,这样的路径的最大权值和。

    我们令当前子树经过的黑点个数为j,前面的子树经过的黑点个数为now,我们显然有:

     maxn[now]=max(maxn[now],maxn[now-1]);

    我们同样显然有:

    if(now+j<=k)ans=max(ans,maxn[now]+t[j]);

    但是显然我们的now不可能全跑一遍(TLE预定),所以我们有两种优化:

      1.now<=s[i-1].first(显然,我们因为sort了所以我们知道now最大不超过s[i-1].first)

      2.j从s[i].first搜到0,期间保证now+j<=k(原因:now越大maxn数组越大所更新的ans越大,所以我们最初就把now放到最大,一来我们更新完了maxn可以不用再更新了,二来此时的maxn[now]+t[j]一定是当前状态最优解。

    咱们继续更新maxn(为了下一步的maxn)

    当当前子树不是最后一棵子树的时候(显然如果是最后一棵的话还更新什么?)显然这么更新即可:maxn[j]=max(maxn[j],t[j]);

    当当前子树是最后一棵子树的时候,我们扫尾将每个子树节点到根节点的距离更新进ans。

  5.删掉重心,递归上述过程。

——————————————————————————————————

好的代码讲解就此结束,最后吐槽一句吧这题卡!常!数!所以把它推向神坛,不然还加那么多奇葩优化干什么……

#include<cmath>
#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int N=;
inline int read(){
int X=,w=; char ch=;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int w;
int to;
int nxt;
}edge[N*];
vector<pair<int,int> >s;
int cnt,n,m,k,head[N],q[N],size[N],son[N],nump[N],fa[N],maxn[N],t[N],ans,d[N],dis[N];
bool vis[N],is[N];
void add(int u,int v,ll w){
cnt++;
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt;
return;
}
int calcg(int st){
int r=,g,maxn=n;
q[++r]=st;
fa[st]=;
for(int l=;l<=r;l++){
int u=q[l];
size[u]=;
son[u]=;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(vis[v]||v==fa[u])continue;
fa[v]=u;
q[++r]=v;
}
}
for(int l=r;l>=;l--){
int u=q[l],v=fa[u];
if(r-size[u]>son[u])son[u]=r-size[u];
if(son[u]<maxn)g=u,maxn=son[u];
if(!v)break;
size[v]+=size[u];
if(size[u]>son[v])son[v]=size[u];
}
return g;
}
inline int getmaxp(int st,ll L){
int r=,maxp=;
q[++r]=st;
nump[st]=is[st];
dis[st]=L;
fa[st]=;
maxp=max(maxp,nump[st]);
for(int l=;l<=r;l++){
int u=q[l];
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
int w=edge[i].w;
if(vis[v]||v==fa[u])continue;
fa[v]=u;
dis[v]=dis[u]+w;
nump[v]=nump[u]+is[v];
maxp=max(maxp,nump[v]);
q[++r]=v;
}
}
return maxp;
}
inline void getmaxt(int st){
int r=;
q[++r]=st;
t[nump[st]]=max(t[nump[st]],dis[st]);
for(int l=;l<=r;l++){
int u=q[l];
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
int w=edge[i].w;
if(vis[v]||v==fa[u])continue;
t[nump[v]]=max(t[nump[v]],dis[v]);
q[++r]=v;
}
}
return;
}
void solve(int u){
int g=calcg(u);
vis[g]=;s.clear();
for(int i=head[g];i;i=edge[i].nxt){
int v=edge[i].to;
int w=edge[i].w;
if(!vis[v])s.push_back(pii(getmaxp(v,w),v));
}
sort(s.begin(),s.end());
if(is[g])k--;
for(int i=;i<s.size();i++){
getmaxt(s[i].second);
int now=;
if(i){
for(int j=s[i].first;j>=;j--){
while(now+j<k&&now<s[i-].first){
now++;
maxn[now]=max(maxn[now],maxn[now-]);
}
if(now+j<=k)ans=max(ans,maxn[now]+t[j]);
}
}
if(i!=s.size()-){
for(int j=;j<=s[i].first;j++){
maxn[j]=max(maxn[j],t[j]);
t[j]=;
}
}else{
for(int j=;j<=s[i].first;j++){
if(j<=k)ans=max(ans,max(t[j],maxn[j]));
maxn[j]=t[j]=;
}
}
}
if(is[g])k++;
for(int i=head[g];i;i=edge[i].nxt){
int v=edge[i].to;
if(!vis[v])solve(v);
}
return;
}
int main(){
n=read();
k=read();
m=read();
for(int i=;i<=m;i++)is[read()]=;
for(int i=;i<n;i++){
int u=read();
int v=read();
int w=read();
add(u,v,w);
add(v,u,w);
}
solve();
printf("%d\n",ans);
return ;
}

SPOJ1825/FTOUR2:Free tour II——包看得懂/看不懂题解的更多相关文章

  1. SPOJ1825 FTOUR2 - Free tour II

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  2. SPOJ FTOUR2 - Free tour II

    Description 有些黑点,问你选择不超过 \(k\) 个黑点的路径,路径权值最大是多少. Sol 点分治. 这是qzc的论文题,不过我感觉他的翻译好强啊...我还是选择了自己去看题目... 点 ...

  3. 【SPOJ1825】Free tour II (点分治,启发式)

    题意: 边权可能为负 思路: 感觉我自己写的还是太过僵硬了,可以灵活一点,比如可以多写几个不同的dfs求出不同的信息,而不是压到同一个dfs里 #include<cstdio> #incl ...

  4. FTOUR2 - Free tour II

    传送门 题目翻译的很清楚……似乎点分治的题题目描述都非常简洁. 还是那个操作,一条路径要么全部在一棵子树中,要么经过当前的重心,所以考虑点分治. 首先dfs求出重心的每一棵子树中,有i个黑点的最长路径 ...

  5. SPOJ1825:Free tour II

    题意 luogu的翻译 给定一棵n个点的树,树上有m个黑点,求出一条路径,使得这条路径经过的黑点数小于等于k,且路径长度最大 Sol 点分治辣 如果是等于\(k\)的话,开个桶取\(max\)就好了 ...

  6. [spoj] FTOUR2 FREE TOUR II || 树分治

    原题 给出一颗有n个点的树,其中有M个点是拥挤的,请选出一条最多包含k个拥挤的点的路径使得经过的权值和最大. 正常树分治,每次处理路径,更新答案. 计算每棵子树的deep(本题以经过拥挤节点个数作为d ...

  7. SP1825 FTOUR2 - Free tour II 点分治+启发式合并+未调完

    题意翻译 给定一棵n个点的树,树上有m个黑点,求出一条路径,使得这条路径经过的黑点数小于等于k,且路径长度最大 Code: #include <bits/stdc++.h> using n ...

  8. SP1825 【FTOUR2 - Free tour II】

    # \(SP1825\) 看到没有人用老师的办法,于是自己写一下思路 思路第一步:排除旧方法 首先这道题和\(4178\)不一样,因为那道题是计数,而这道题是求最值,最值有个坏处,就是对于来自相同子树 ...

  9. BZOJ2694:Lcm——包看得懂/看不懂题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2694 Description 对于任意的>1的n gcd(a, b)不是n^2的倍数 也就是说 ...

随机推荐

  1. javaweb(五)——Servlet开发(一)

    一.Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向 ...

  2. AirtestIDE实践二:Poco框架试用

    上一篇用airtest框架做了一个梦幻西游手游的DEMO,这次看看poco的强大之处.首先安装poco:pip install pocoui 其次,把SDK集成到你家游戏中,我这直接用官网提供的一个U ...

  3. 关于java获取网页内容

    最近项目需求,做一些新闻站点的爬取工作.1.简单的jsoup爬取,静态页面形式: String url="a.atimo.cn";//静态页面链接地址Document doc = ...

  4. [Clr via C#读书笔记]Cp6类型和成员基础

    Cp6类型和成员基础 成员 常量:字段(静态字段和实例字段):实例构造器:类型构造器(用于静态字段的构造):方法(静态方法和实例方法):操作符重载(本质是一个方法):转换操作符:属性(本质还是方法): ...

  5. jmeter链接数据库问题汇总

    1.最新驱动下载: 驱动版本与mysql服务不兼容也是会报错的 下载地址:https://dev.mysql.com/downloads/connector/j/ 打开页面一直拉到页面底部,此处选择P ...

  6. pymsql报错:UnicodeEncodeError: 'latin-1' codec can't encode characters End,OK!!

    UnicodeEncodeError: 'latin-1' codec can't encode characters的做法基本一致,后来发现是因为使用的是mysqldb,照着网上的方法修改配置应该可 ...

  7. 【Linux 运维】 Centos7.x 系统修复模式

    一.linux的运行级别: 运行级别就是来确定系统启动时到底启动那个服务. linux默认有7个运行级别: 0 关机 1 单用户模式,用于系统修复 2 不完全的命令模式,不含NFS服务 3 完全的命令 ...

  8. python常用命令—windows终端查看安装包信息

    1, pip list 会将 Python 的所有安装包全部显示出来, 左边是包名, 右边是包的版本号. 2, pip show 包的名字 会将这个包的名字,版本号,包的功能说明,按装这个包的路径显示 ...

  9. Python学习之路1 - 基础入门

    本文内容 Python介绍 安装Python解释器 输出 变量 输入 条件判断语句 循环语句 模块讲解 三元运算 字符串和二进制的相互转化 本系列文章使用的Python版本为3.6.2 使用开发工具为 ...

  10. 20162328蔡文琛week02

    学号 20162328 <程序设计与数据结构>第2周学习总结 教材学习内容总结 这周学习了课本中的第二章内容,比起第一章,本章难度有略微底稿,从刚开始的显示字符转变为简单的加减乘除运算,经 ...