淀粉质入门第一道 (现在个人认为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\)个带标记节点的路径的最大长度..

那我们就可以得到:

\[ans=max\{mx[t]+dis[x]\} (dep[x]+t<=k)
\]

但是这个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 点分治的更多相关文章

  1. 【学术篇】CF833B TheBakery 分治dp+主席树

    题目の传送门~ 题目大意: 将\(n\)个蛋糕分成恰好\(k\)份, 求每份中包含的蛋糕的种类数之和的最大值. 这题有两种做法. 第一种是线段树优化dp, 我还没有考虑. 另一种就是分治+主席树. 然 ...

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

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

  3. SPOJ - FTOUR2 (点分治+树状数组)

    题目:https://vjudge.net/contest/307753#problem/I 题意:有一颗树,上面有白色黑色点,每个点上有一个权值,权值可以为负,现在我要求一条路径,权值和最大,这条路 ...

  4. 【学术篇】SPOJ GEN Text Generator AC自动机+矩阵快速幂

    还有5天省选才开始点字符串这棵技能树是不是太晚了点... ~题目の传送门~ AC自动机不想讲了QAQ.其实很久以前是学过然后打过板子的, 但也仅限于打过板子了~ 之前莫名其妙学了一个指针版的但是好像不 ...

  5. 【学术篇】bzoj3262 陌上花开. cdq分治入门

    花儿们已经很累了-- 无论是花形.颜色.还是气味, 都不是为了给人们摆出来欣赏的, 更不是为了当做出题的素材的, 她们并不想自己这些属性被没有生命的数字量化, 并不想和其它的花攀比, 并无意分出个三六 ...

  6. 【学术篇】SPOJ QTREE 树链剖分

    发现链剖这东西好久不写想一遍写对是有难度的.. 果然是熟能生巧吧.. WC的dalao们都回来了 然后就用WC的毒瘤题荼毒了我们一波, 本来想打个T1 44分暴力 然后好像是特判写挂了还是怎么的就只能 ...

  7. 【学术篇】SPOJ COT 树上主席树

    这是学完主席树去写的第二道题_(:з」∠)_ 之前用树上莫队水过了COT2... 其实COT也可以用树上莫队水过去不过好像复杂度要带个log还是怎么样可能会被卡常数.. 那就orz主席吧.... 写了 ...

  8. 【学术篇】一些水的不行的dp

    最近做了几道非常水非常水的dp...... 之后刷的一些水dp也会写在这里...... 此篇题目难度不递增!!! Emmmm....... 1.luogu1043数字游戏 以前看过这个题几遍,没做这个 ...

  9. SPOJ FTOUR2 - Free tour II

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

随机推荐

  1. elementUI 的el-pagination 分页功能

    <div class="block1"> <el-pagination @size-change="handleSizeChange" @cu ...

  2. mySQL学习入门教程——2.创建表

    二.创建表 一.创建数据表的SQL语句模型(弱类型)CREATE TABLE [IF NOT EXISTS] 表名称(字段名1 列的类型[属性][索引],字段名2 列的类型[属性][索引],-字段名n ...

  3. JAVA学习,边学习边总结边记录

    纯属个人想法,个人感觉,有什么不足之处,还望看到的人指正. 我将一步一步的往下记录下去,后面会加一个基本完整的程序,敬请期待. 一.java基础 二.java面向对象 三.html,jsp 四.Jav ...

  4. http(python)

    1.client 1) httpie http -f POST example.org hello=World http POST http://192.168.200.251:55101/Api/C ...

  5. Ti 949 配置 948 i2c

    如果不想用 远端 slave,只访问948   选 i2c pass through all =1  :i2c pass through =0/1 0x0c 0x17 0x9e 如果想用远端  sla ...

  6. Python 基础 2-1 列表入门

    引言 列表 list 是由一系列按照特定顺序排列的元素组成的,它是一种有序的数据集合. 你可以添加任何类型的元素到列表中,其中的元素之间可以没有任何关系. 列表简介 Python 使用方括号 [] 来 ...

  7. 项目案例之GitLab的数据迁移

    项目案例之GitLab的数据迁移 链接:https://pan.baidu.com/s/1CgaEv12cwfbs5RxcNpxdAg 提取码:fytm 复制这段内容后打开百度网盘手机App,操作更方 ...

  8. 利用Process类创建多个子进程对象执行任务,主进程负责调度

    import time from multiprocessing import Process def run1(): for i in range(5): print("sunck is ...

  9. PHP-两数相除

    给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 1: 输 ...

  10. vue中key的作用

    1.v-if中用key管理可复用的元素  Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染.这么做,除了使 Vue 变得非常快之外,还有一些有用的好处.例如,如果你允许用户在不同的 ...