淀粉质入门第一道 (现在个人认为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. maven工程的下载及其环境配置

    Maven是一个项目管理工具,它给我们提供了好多有用的组件和工具. Maven下载: Maven下载载地址:http://maven.apache.org/download.cgi (1)进入下载界面 ...

  2. HTTP、HTTP1.0、HTTP1.1、HTTP2.0、HTTPS

      一.HTTP HTTP(超文本传输协议,HyperText Transfer Protocol)是应用层的协议,目前在互联网中应用广泛. 它被设计用于Web浏览器和Web服务器之间的通信,但它也可 ...

  3. 微信小程序的加载机制和运行机制

    一.运行机制 冷启动指的是重新启动,热启动指的是5分钟内从后台切换到前台,只有冷启动才能加载最新的包. 小程序什么时候会关闭? 5min后台运行,连续收到两次(2s)系统告警. 二.加载机制 三.小程 ...

  4. printf 格式化打印 awk 数据处理工具

    printf解析 这个玩意说白了,就是格式化打印输出. awk awk与sed都是处理数据的工具.sed是处理整行的数据,awk则比较倾向于一行当中分成数个[字段]来处理. 具体操作: 注意的几个点 ...

  5. yum 命令跳过特定(指定)软件包升级方法

    今天在更新rhel的时候,遇到了yum update 更新失败,一些包的依赖关系有问题,报出了需要rpm_check_debug的信息. 我man 一下rpm的命令没有看到check相关的选项,也就没 ...

  6. React defaultProps

    defaultProps // 为属性指定默认值:Greeting.defaultProps = { name: 'Stranger'}; defaultProps 用来确保 this.props.n ...

  7. vue-resource请求

    man.js引入 import Vue from 'vue' import VueResource from 'vue-resource' import App from './App.vue' Vu ...

  8. 【Redis】分布式锁RedLock

    普通实现 说道Redis分布式锁大部分人都会想到: 1.setnx+lua, 2.setkey value px milliseconds nx. - 获取锁(unique_value可以是UUID等 ...

  9. 【NOIP2019模拟2019.9.4】B(期望的线性性)

    题目描述: \(1<=n,ai<=5*10^5\) 题解: 我是弱智我不会期望线性. 设\(E(a[i])\)表示第i个期望被减的个数. \(E(a[1])=a[1]\) 不难发现\(E( ...

  10. 配置Redis集群为开机自启动

    vim /etc/init.d/redisc 将下方脚本写入redisc文件中 #!/bin/sh # chkconfig: 2345 80 90 # # Simple Redis init.d sc ...