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. mac使用brew或者tomcat启动jenkins后配置文件路径

    在mac下使用brew命令或tomcat安装jenkins,启动后要输入密码,密码不知道,又找不到config.xml,找了半天原来 config.xml在/Users/qiaojiafei/.jen ...

  2. 第四十篇 Python之设计模式总结-简单工厂、工厂方法、抽象工厂、单例模式

    一. 简单工厂 简单工厂模式(Simple Factory Pattern):是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类. 简单工厂的用处不大,主要就是一个if... ...

  3. 初学Direct X (2)

    初学Direct X (2) 这一次要学习如何现实位图,尽管看过对双缓冲机制还有很多疑问,但是这并不阻碍我对他的入门了解 Direct3D提供了一个双重/后台缓冲区,在调用CreateDevice之时 ...

  4. JS变量定义时连续赋值的坑!

    在定义变量时,可以将值相同的变量采用连续赋值的方式,如下代码: var a = b = c = ''; 其实这里面有一个很大很大的坑,以代码说明问题: <script language=&quo ...

  5. #pragma pack(n)对齐格式

    #pragma pack(n)对齐格式 #pragma pack(n) 是预处理器用来指定对齐格式的指令,表示n对齐.当元素字节小于n时,要扩展到n:若元素字节大于n则占用其实际大小. struct ...

  6. 互评Alpha版本——Thunder团队

    基于NABCD评论作品 Hello World! :http://www.cnblogs.com/120626fj/p/7807544.html 欢迎来怼 :http://www.cnblogs.co ...

  7. POJ 2823 (滑动窗口)

    这道题最容易想到的是用朴素的做法,即 每滑动一次,就遍历一次窗口找出最大最小值,这样时间复杂度为O(n*k),由于题目数据比较大,这种做法肯定是超时的. 另外,根据书上的讲解,还可以采用优先队列来求解 ...

  8. PHP 签到,与时间获取,数组长度获取

    本文实例讲述了php实现签到功能的方法.分享给大家供大家参考,具体如下:首先我在数据库里建了两张表,一个是用户的积分表,一个是签到状态表,分来用来记录用户的积分数和先到状态 在用户签到状态表中我们有一 ...

  9. Acm hust 1.25

    闲着无聊做了点hust上 acm的训练题 A题 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=104738#problem/A 看了20分 ...

  10. Java中Collection和Collections的区别(转载)

    转载来源:http://www.cnblogs.com/dashi/p/3597937.html 1.java.util.Collection 是一个集合接口(集合类的一个顶级接口).它提供了对集合对 ...