Description

有些黑点,问你选择不超过 \(k\) 个黑点的路径,路径权值最大是多少.

Sol

点分治.

这是qzc的论文题,不过我感觉他的翻译好强啊...我还是选择了自己去看题目...

点分治每次至少分一半,所以层数不超过过 \(logn\) 每次分治只考虑过根节点的情况.

我们想想如何统计答案.

\(f[i][j]\) 表示 \(i\) 节点的子树拥有 \(j\) 个黑点最大的边权.

\(g[i][j]\) 表示 \(i\) 节点的子树拥有不超过 \(j\) 个黑点的最大边权.

\(d[i]\) 表示 \(i\) 节点的子树中黑点的个数(或者表示成一条链上最多的黑点个数都可以).

然后就可以这样更新在最坏情况下是 \(O(nk)\) 的,但是我们如果按 \(d[i]\) 排一下序,从小到大更新,这样的更新的复杂度就是 \(O(\sum d_i)\) ,因为黑点个数是有限的,所以更新的复杂度就不超过 \(O(n)\) 了.

这样点分治一个 \(log\) ,排序一个 \(log\) ,所以总复杂度为 \(O(nlog^2n)\) .

感觉这道题也好强啊qwq..分治算法各种神奇..

Code

#include <bits/stdc++.h>
using namespace std; #define mpr make_pair
#define debug(a) cout<<#a<<"="<<a<<" " typedef pair< int,int > pr;
const int N = 2e5+50;
const int INF = 0x3f3f3f3f; int n,k,m; pr edge[N<<1];
int h[N],nxt[N<<1],cnte; int rt,ans;
int sz[N],t[N],usd[N];
pr d[N];
int f[N],g[N],bl[N]; inline int in(int x=0,char ch=getchar(),int v=1) {
while(ch>'9' || ch<'0') v=(ch=='-'?-1:v),ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x*v;
}
void Add_Edge(int fr,int to,int w) {
edge[++cnte]=mpr(to,w),nxt[cnte]=h[fr],h[fr]=cnte;
} void GetRoot(int u,int fa,int nn) {
sz[u]=1,t[u]=0;
for(int i=h[u],v;i;i=nxt[i]) if(!usd[v=edge[i].first] && v!=fa) {
GetRoot(v,u,nn),sz[u]+=sz[v],t[u]=max(t[u],sz[v]);
}t[u]=max(t[u],nn-sz[u]);
if(t[u]<t[rt]) rt=u;
} int GetD(int u,int fa) {
int td=bl[u];
for(int i=h[u],v;i;i=nxt[i]) if(!usd[v=edge[i].first] && v!=fa) {
td+=GetD(v,u);
}return td;
}
void GetF(int u,int fa,int c,int w) {
f[c]=max(f[c],w);
for(int i=h[u],v;i;i=nxt[i]) if(!usd[v=edge[i].first] && v!=fa) {
// cout<<u<<"-->"<<v<<" "<<c+bl[u]<<" "<<w+edge[i].second<<endl;
GetF(v,u,c+bl[v],w+edge[i].second);
}
}
void GetAns(int u,int n) {
usd[u]=1;int c=0;
for(int i=h[u],v;i;i=nxt[i]) if(!usd[v=edge[i].first]){
d[++c]=mpr(GetD(v,u),i);
}
sort(d+1,d+c+1);
int mxd=0,tt=min(k-bl[u],d[c].first),v,mx=0;
for(int i=0;i<=tt;i++) g[i]=-INF;
for(int i=1;i<=c;i++) {
tt=min(d[i].first,k-bl[u]);
for(int j=0;j<=tt;j++) f[j]=-INF;
v=edge[d[i].second].first;
GetF(v,u,bl[v],edge[d[i].second].second); // cout<<v<<" --> f[]"<<endl;
// for(int j=0;j<=tt;j++) cout<<f[j]<<" ";cout<<endl; for(int j=0,pp;j<=tt;j++) pp=min(mxd,k-bl[u]-j),ans=(g[pp]!=-INF&&f[j]!=-INF)?max(ans,g[pp]+f[j]):ans; for(int j=0;j<=tt;j++) g[j]=max(g[j],f[j]); // cout<<"g[]"<<endl;
// for(int j=0;j<=tt;j++) cout<<g[i]<<" ";cout<<endl; mxd=tt,mx=0;
for(int j=0;j<=mxd;j++) mx=max(mx,g[j]),g[j]=mx;
} ans=max(ans,g[mxd]); // debug(u)<<":"<<endl;
// for(int i=1;i<=c;i++) cout<<d[i].first<<" "<<edge[d[i].second].first<<endl;
// debug(ans)<<endl;
// cout<<"----------------------"<<endl; for(int i=h[u],v,nn;i;i=nxt[i]) if(!usd[v=edge[i].first]) {
rt=0,nn=sz[v]>sz[u] ? n-sz[u]: sz[v],GetRoot(v,v,nn),GetAns(rt,nn);
}
} int main() {
n=in(),k=in(),m=in();
for(int i=1,x;i<=m;i++) x=in(),bl[x]=1;
for(int i=1,u,v,w;i<n;i++)
u=in(),v=in(),w=in(),Add_Edge(u,v,w),Add_Edge(v,u,w); t[0]=n+1,rt=0,GetRoot((n+1)>>1,(n+1)>>1,n);
GetAns(rt,n); cout<<ans<<endl;
return 0;
} /*
8 2 3
3
5
7
1 3 1
2 3 10
3 4 -2
4 5 -1
5 7 6
5 6 5
4 8 3 12
*/

SPOJ FTOUR2 - Free tour II的更多相关文章

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

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

  2. SPOJ 1825 Free tour II (树的点分治)

    题目链接 Free tour II 题意:有$N$个顶点的树,节点间有权值, 节点分为黑点和白点. 找一条最长路径使得 路径上黑点数量不超过K个 这是树的点分治比较基本的题,涉及树上启发式合并……仰望 ...

  3. spoj 1825 Free tour II

    http://www.spoj.com/problems/FTOUR2/ After the success of 2nd anniversary (take a look at problem FT ...

  4. SPOJ1825 FTOUR2 - Free tour II

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

  5. SPOJ:Free tour II (树分治+启发式合并)

    After the success of 2nd anniversary (take a look at problem FTOUR for more details), this 3rd year, ...

  6. SPOJ 1825 Free tour II 树分治

    题意: 给出一颗边带权的数,树上的点有黑色和白色.求一条长度最大且黑色节点不超过k个的最长路径,输出最长的长度. 分析: 说一下题目的坑点: 定义递归函数的前面要加inline,否则会RE.不知道这是 ...

  7. FTOUR2 - Free tour II

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

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

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

  9. SP1825 【FTOUR2 - Free tour II】

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

随机推荐

  1. C#记录程序运行时间记录显示

    //引入命名空间            using System.Diagnostics;            //清空导入时间 lbImportTime.Text = ""; ...

  2. 【BZOJ-2119】股市的预测 后缀数组

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 334  Solved: 154[Submit][Status][Discuss ...

  3. DedeCMS flink_add Getshell漏洞 管理员CSRF漏洞

    DedeCMS flink_add Getshell漏洞 管理员CSRF漏洞 1.漏洞利用 由于tpl.php中的$action,$content,$filename变量没有初始化,从而能操纵这些变量 ...

  4. mysql主从复制操作步骤

    注: .做主从复制的两台服务器server-id不能相同 .主从的字符集要一样,不然数据导入会报错 .开启db01的log-bin功能 [root@db01 mysql]# vim /etc/my.c ...

  5. BZOJ1492: [NOI2007]货币兑换Cash

    设$x_j$,$y_j$为第$j$天能买的A,B券数量,$f_i$为第$i$天的最大收益.$f_i=\max_{1\le j<i}a_ix_j+b_iy_j$,最大化$f_i$即找一个点$(x_ ...

  6. C#基础强化-继承与多态

    /**  特性:    单根性:一个子类只能有一个父类    传递性:爷爷类 爹类 儿子类  里氏转换    1.子类可以赋值给父类    2.如果父类装的是子类对象,则可以将这个父类转换为对应的子类 ...

  7. java ---- 面试题

    1.java 语言如何进行异常处理,关键字:throws.throw.try.catch.finally分别代表什么意义?finally代码是在return之后还是之前执行? throws是获取异常, ...

  8. ios开发之Info.plist文件相关配置

    前言:在iOS开发中有些情况下需要对Info.plist文件进行配置,以下介绍几种相关配置.以后遇到需要配置的再更新... 开发环境:swift3.0.1,Xcode8.1 一,项目中需要使用第三方字 ...

  9. Netty源码分析之服务端启动过程

    一.首先来看一段服务端的示例代码: public class NettyTestServer { public void bind(int port) throws Exception{ EventL ...

  10. UML大战需求分析--阅读笔记3

    这次阅读的是第四章,流程分析利器之 – 活动图.对需求有两种分析的方式:结构建模与行为建模.活动图是行为建模中经常使用的一种图.由流程图发展而来. 活动图中有一些名词:开始状态.结束状态.活动.判断. ...