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. protected修饰符详解

    protected这个修饰符,各大参考书都会这样说:访问权限为类内,包内和子类,因此在父类中定义的方法和成员变量如果为protected修饰的,是可以在不同包中的子类进行访问的,示例代码如下: pac ...

  2. AIX7.1删除大批量文件(百万级、千万级)

    假设/data/test目录下含有数百万上千万的文件需要删除,可以选择的方式如下: 1.如果文件名不包含空白符.引号等特殊字符,则可以使用如下命令: find /data/test -type f | ...

  3. hdu1869六度分离(floyd)

    六度分离 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  4. Selenium 入门到精通系列:二

    Selenium 入门到精通系列 PS:用户登录 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019-04-23 16:12 ...

  5. 第5章 Linux网络编程基础

    第5章 Linux网络编程基础 5.1 socket地址与API 一.理解字节序 主机字节序一般为小端字节序.网络字节序一般为大端字节序.当格式化的数据在两台使用了不同字节序的主机之间直接传递时,接收 ...

  6. 孤荷凌寒自学python第八十一天学习爬取图片1

    孤荷凌寒自学python第八十一天学习爬取图片1 (完整学习过程屏幕记录视频地址在文末) 通过前面十天的学习,我已经基本了解了通过requests模块来与网站服务器进行交互的方法,也知道了Beauti ...

  7. OpenMPI源码剖析2:ompi_mpi_errors_are_fatal_comm_handler函数

    上一篇文章说道,初始化失败会有一个函数调用: ompi_mpi_errors_are_fatal_comm_handler(NULL, NULL, message); 所以这里简单地进入了 ompi_ ...

  8. (原创)白话KMP算法详解

    引子:BF暴力算法 KMP算法知名度相当高,燃鹅其理解难度以及代码实现对于初学数据结构和算法的同学并不友好,经过两天的总结,详细总结KMP算法如下: 初学串的模式匹配时,我们都会接触到,或者说应该能想 ...

  9. python常用命令—‘\r’

    # \r 默认表示将输出的内容返回到第一个指针,这样的话,后面的内容会覆盖前面的内容 如常用的显示程序完成进度!!

  10. 从Softmax回归到Logistic回归

    Softmax回归是Logistic回归在多分类问题上的推广,是有监督的. 回归的假设函数(hypothesis function)为,我们将训练模型参数,使其能够最小化代价函数: 在Softmax回 ...