【学术篇】SPOJ FTOUR2 点分治
淀粉质入门第一道 (现在个人认为spoj比bzoj要好_(:з」∠)_
关于点分治的话推荐去看一看漆子超的论文>>>这里这里<<<
之前一直试图入点分治坑, 但是因为种(bu)种(duan)原(tui)因(fei)也没有入...
结果经常碰到点分治的题目... 然后就各种弃疗...
不少点分治的题目有非常明显的特征... 通常是给一棵树, 然后问你满足xx条件的路径有多少条/是否存在/最大(小)权值之类的...
然后点分治的做法也不尽相同 大致能写出如下的伪代码(好吧还是用python高亮)
def solve(x): # 处理以x为根的子树
vis[x]=1 # 把x标记为操作过(视为删掉)
findroot(x) # 找到以x为根的子树的重心
calc(x) # 统计过x的路径的答案
for i in son[x]: # 对于每个儿子
solve(i) # 递归处理答案
然后刚入门第一道就不能算是很裸的点分治_(:з」∠)_
几乎抄了黄学长的代码, 在此表示感谢..
<题目の传送门>
hzwer题解の传送门
题目大意:
给一棵树, 有\(m\)个点上有一个标记, 边有边权, 可正可负.
询问路径上带标记的点不超过\(k\)个的路径的最大权值是多少.
首先朴素的思路就是暴力嘛... 复杂度\(O(n^2)\)的.. 可能能拿30~40(但这是spoj所以并没有什么部分分..)
我们要考虑复杂度更好的做法.. 首先根据上面我们说过的特征, 可以看出这题应该可以用点分治做...
因为后面是递归处理的, 我们只需要考虑如何统计合法的过根节点的路径的答案就行了..
我们需要处理出\(dep[y]\)和\(dis[y]\)两个数组, 分别表示\(y\)到当前的根节点(以下的根节点均指当前子树的根节点, 因为原来的根节点处理过就删掉了)的路径上的带标记节点个数和路径权值和. 这个可以通过一遍dfs\(O(n)\)完成...
然后我们考虑有哪些路径会对答案产生影响...
假如我们要处理\(x\)的\(i\)个子树, 那么前\(i-1\)个子树中的点可以与这个子树中的点确定一条路径.
我们再用一遍\(O(n)\)的dfs处理出\(mx[t]\)这个数组, 表示从前\(i-1\)棵子树中到根节点的经过\(t\)个带标记节点的路径的最大长度..
那我们就可以得到:
\]
但是这个dep[x]是会变的, 所以我们可以把儿子按照dep排序一波再做, 就可以顺着推过去了, 据说这样的复杂度是\(O(n)\)级别的..
然后排序的话总共也就只是\(O(nlogn)\)级别的东西, 配合着点分治的复杂度, 最后就是\(O(nlogn)\)咯..
代码:
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define depth first
#define id second
const int N=202020;
inline int gn(int a=0,char c=0,int f=1){
for(;(c<48||c>57)&&c!='-';c=getchar());if(c=='-')c=getchar(),f=-1;
for(;c>47&&c<58;c=getchar()) a=a*10+c-'0'; return a*f;
}
struct edge{
int to,next,data;
}e[N<<1]; int v[N],tot,n,m,k,rt,size,ans;
void buildedge(int x,int y,int z){
e[++tot].to=y; e[tot].next=v[x]; v[x]=tot; e[tot].data=z;
e[++tot].to=x; e[tot].next=v[y]; v[y]=tot; e[tot].data=z;
}
int q[N],fa[N],son[N],sz[N],mx[N],tmp[N],dep[N],d[N],depmx;
bool vis[N],a[N];
void findrt(int x,int fa){
sz[x]=1; son[x]=0;
for(int i=v[x];i;i=e[i].next)
if(!vis[e[i].to]&&e[i].to!=fa){
findrt(e[i].to,x);
son[x]=max(son[x],sz[e[i].to]);
sz[x]+=sz[e[i].to];
}
son[x]=max(son[x],size-sz[x]);
if(son[x]<son[rt]) rt=x;
}
void calcdis(int x,int fa){
depmx=max(depmx,dep[x]);
for(int i=v[x];i;i=e[i].next)
if(!vis[e[i].to]&&e[i].to!=fa){
dep[e[i].to]=dep[x]+a[e[i].to];
d[e[i].to]=d[x]+e[i].data;
calcdis(e[i].to,x);
}
}
void calcmax(int x,int fa){
tmp[dep[x]]=max(tmp[dep[x]],d[x]);
for(int i=v[x];i;i=e[i].next)
if(!vis[e[i].to]&&e[i].to!=fa)
calcmax(e[i].to,x);
}
vector<pair<int,int> > vec;
void solve(int x){
vis[x]=1; vec.clear(); if(a[x]) --k;
for(int i=v[x];i;i=e[i].next)
if(!vis[e[i].to]){
depmx=0;
dep[e[i].to]=a[e[i].to];
d[e[i].to]=e[i].data;
calcdis(e[i].to,x);
vec.push_back(make_pair(depmx,e[i].to));
}
sort(vec.begin(),vec.end());
for(int i=0;i<vec.size();++i){
calcmax(vec[i].id,x);
int now=0;
if(i!=0)
for(int j=vec[i].depth;j>=0;--j){
while(now+j<k&&now<vec[i-1].depth)
++now,mx[now]=max(mx[now],mx[now-1]);
if(now+j<=k) ans=max(ans,mx[now]+tmp[j]);
}
if(i!=vec.size()-1)
for(int j=0;j<=vec[i].depth;++j)
mx[j]=max(mx[j],tmp[j]),tmp[j]=0;
else
for(int j=0;j<=vec[i].depth;++j){
if(j<=k) ans=max(ans,max(tmp[j],mx[j]));
tmp[j]=mx[j]=0;
}
}
if(a[x]) ++k;
for(int i=v[x];i;i=e[i].next)
if(!vis[e[i].to]){
rt=0; size=sz[e[i].to];
findrt(e[i].to,x);
solve(rt);
}
}
int main(){
n=gn(),k=gn(),m=gn();
for(int i=1;i<=m;++i) a[gn()]=1;
for(int i=1;i<n;++i){
int x=gn(),y=gn(),z=gn();
buildedge(x,y,z);
}
size=son[0]=n; findrt(1,0);
solve(rt);
printf("%d",ans);
}
【学术篇】SPOJ FTOUR2 点分治的更多相关文章
- 【学术篇】CF833B TheBakery 分治dp+主席树
题目の传送门~ 题目大意: 将\(n\)个蛋糕分成恰好\(k\)份, 求每份中包含的蛋糕的种类数之和的最大值. 这题有两种做法. 第一种是线段树优化dp, 我还没有考虑. 另一种就是分治+主席树. 然 ...
- [spoj] FTOUR2 FREE TOUR II || 树分治
原题 给出一颗有n个点的树,其中有M个点是拥挤的,请选出一条最多包含k个拥挤的点的路径使得经过的权值和最大. 正常树分治,每次处理路径,更新答案. 计算每棵子树的deep(本题以经过拥挤节点个数作为d ...
- SPOJ - FTOUR2 (点分治+树状数组)
题目:https://vjudge.net/contest/307753#problem/I 题意:有一颗树,上面有白色黑色点,每个点上有一个权值,权值可以为负,现在我要求一条路径,权值和最大,这条路 ...
- 【学术篇】SPOJ GEN Text Generator AC自动机+矩阵快速幂
还有5天省选才开始点字符串这棵技能树是不是太晚了点... ~题目の传送门~ AC自动机不想讲了QAQ.其实很久以前是学过然后打过板子的, 但也仅限于打过板子了~ 之前莫名其妙学了一个指针版的但是好像不 ...
- 【学术篇】bzoj3262 陌上花开. cdq分治入门
花儿们已经很累了-- 无论是花形.颜色.还是气味, 都不是为了给人们摆出来欣赏的, 更不是为了当做出题的素材的, 她们并不想自己这些属性被没有生命的数字量化, 并不想和其它的花攀比, 并无意分出个三六 ...
- 【学术篇】SPOJ QTREE 树链剖分
发现链剖这东西好久不写想一遍写对是有难度的.. 果然是熟能生巧吧.. WC的dalao们都回来了 然后就用WC的毒瘤题荼毒了我们一波, 本来想打个T1 44分暴力 然后好像是特判写挂了还是怎么的就只能 ...
- 【学术篇】SPOJ COT 树上主席树
这是学完主席树去写的第二道题_(:з」∠)_ 之前用树上莫队水过了COT2... 其实COT也可以用树上莫队水过去不过好像复杂度要带个log还是怎么样可能会被卡常数.. 那就orz主席吧.... 写了 ...
- 【学术篇】一些水的不行的dp
最近做了几道非常水非常水的dp...... 之后刷的一些水dp也会写在这里...... 此篇题目难度不递增!!! Emmmm....... 1.luogu1043数字游戏 以前看过这个题几遍,没做这个 ...
- SPOJ FTOUR2 - Free tour II
Description 有些黑点,问你选择不超过 \(k\) 个黑点的路径,路径权值最大是多少. Sol 点分治. 这是qzc的论文题,不过我感觉他的翻译好强啊...我还是选择了自己去看题目... 点 ...
随机推荐
- Jsoup爬虫任务总结
这两周由于公司需要大量数据爬取进数据库给用户展示素材,在不停的做爬虫工作,现在总算基本完成就剩清理数据的工作: 公司有一个采集器管理后台的项目,可以直接把爬虫代码打包成jar导入进去设置定时参数即可: ...
- WPF 动态添加控件以及样式字典的引用(Style introduction)
原文:WPF 动态添加控件以及样式字典的引用(Style introduction) 我们想要达到的结果是,绑定多个Checkbox然后我们还可以获取它是否被选中,其实很简单,我们只要找到那几个关键的 ...
- 循序渐进学.Net Core Web Api开发系列【13】:中间件(Middleware)【有源码】
原文:循序渐进学.Net Core Web Api开发系列[13]:中间件(Middleware) 系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:ht ...
- element ui step组件在另一侧加时间轴显示
这是我开发的时候遇到的一个问题:项目需要在步骤条(竖直方向)的另一侧加时间显示,但是我在element ui 的step组件中一直没找着设置方法,所以就自己想了个办法加进来,效果如下: 代码如下,先上 ...
- offset 、 client 和 scroll - PC端网页特效
1.元素偏移量 offset 系列 1.1 offset 就是偏移量,使用 offset 系列相关属性可以 动态 得到该元素的位置(偏移).大小等. 注意: 1.获得元素距离带有定位父元素的位置 2 ...
- 安装 sysbench的 报错 /usr/bin/ld: cannot find -lmysqlclient_r 解决办法
首先你需要找到这个库的位置 一般找的话需要将lib 给加上(注意:我这里是 -lmysqlclient_r 的报错,于是我找就找 libmysqlclient_r ) find / -name lib ...
- SNAT 和 DNAT
SNAT是原地址转换,DNAT是目标地址转换. SNAT 内部地址要访问公网上的服务时,内部地址会主动发起连接,将内部地址转换成公有ip.网关这个地址转换称为SNAT 企业内部的主机A想访问互联网上的 ...
- shell脚本每五分钟执行一次可执行程序(nohup)
两种解决方案:个人推荐第二种,使用crontab来定时执行任务 1.shell代码如下: nohup command &. 解释: 后台永久运行command命令. (nohup表示后台永 ...
- 分布式项目spring 配置文件的约束
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...
- Linux中网卡配置/etc/sysconfig/network-script/ifcfg-eth0
网络接口配置文件 [root@localhost ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth0 TYPE=Ethernet #网卡类型 DEVIC ...