Race bzoj-2599

    题目大意:询问一颗树上最短的、长度为k的链,边有边权,n个节点。

    注释:$1\le n \le 2\cdot 10^5$,$1\le k \le 10^6$。

      想法:树上点分治的另一种表现方式。首先,由于题目中要求的是最小值,我们发现这东西可加不可减。不可减意味着什么?意味着我们递归计算当前树时无法将它的单个子树的情况减掉。所以之前的单步容斥的算法就收到了打压qwq。我们思考另一种方法。首先,类似于dfs的,我一定是对于当前root一颗子树一颗子树地递归,只有当前子树的信息已经完全处理好的情况下我才会去处理下一颗子树。这就相当于我在处理当前子树的时候之前的子树已经是完善的了。所以,我可以开一个桶,记录长度为i的链的最短长度,然后对于当前子树我可以直接调用桶中信息,即可。然后,还原桶的操作是简单的,就是说如果当前桶所代表的边权小于等于k,那么久有可能是被更新过的,将其还原即可。

    最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
using namespace std;
const int inf=1<<30;
int to[2*N],nxt[2*N],head[N],val[N*2],tot;
int size[N],vis[N],v[N*5],f[N],dis[N],deep[N];
//dis数组表示当前节点到根节点之间的边权和
//deep数组表示当前节点到根节点路径深度,即链长度
//vis数组表示当前节点是否已经被删除(当过根节点)
//v数组是桶
int ms,root;
int n,k;
int ans=inf;
inline void add(int x,int y,int z)//加边
{
to[++tot]=y;
val[tot]=z;
nxt[tot]=head[x];
head[x]=tot;
}
void getroot(int pos,int fa)//找重心、处理size
{
size[pos]=1;
f[pos]=0;
for(int i=head[pos];i;i=nxt[i])
{
if(to[i]==fa||vis[to[i]]) continue;
getroot(to[i],pos);
size[pos]+=size[to[i]];
f[pos]=max(size[to[i]],f[pos]);
}
f[pos]=max(f[pos],ms-size[pos]);
if(f[root]>f[pos]) root=pos;
// puts("getroot");
}
void clear(int pos,int fa)//还原桶
{
if(dis[pos]<=k) v[dis[pos]]=inf;
for(int i=head[pos];i;i=nxt[i])
{
if(to[i]==fa||vis[to[i]]) continue;
clear(to[i],pos);
}
// puts("clear");
}
void insert(int pos,int fa)//修改桶
{
if(dis[pos]<=k)
{
v[dis[pos]]=min(v[dis[pos]],deep[pos]);
}
for(int i=head[pos];i;i=nxt[i])
{
if(vis[to[i]]||to[i]==fa) continue;
insert(to[i],pos);
// puts("insert");
}
}
void calc(int pos,int fa)//计算答案
{
if(dis[pos]<=k)
{
ans=min(ans,deep[pos]+v[k-dis[pos]]);
}
for(int i=head[pos];i;i=nxt[i])
{
if(vis[to[i]]||to[i]==fa) continue;
deep[to[i]]=deep[pos]+1;
dis[to[i]]=dis[pos]+val[i];
calc(to[i],pos);
}
// puts("calc");
}
void solve(int pos)//点分治过程
{
vis[pos]=true;
// deep[pos]=0;
v[0]=0;
for(int i=head[pos];i;i=nxt[i])
{
if(vis[to[i]]) continue;
deep[to[i]]=1;
dis[to[i]]=val[i];
calc(to[i],0);
insert(to[i],0);
}
for(int i=head[pos];i;i=nxt[i])
{
if(vis[to[i]]) continue;
clear(to[i],0);
}
for(int i=head[pos];i;i=nxt[i])
{
if(vis[to[i]]) continue;
ms=size[to[i]];
root=0;
getroot(to[i],0);
solve(root);
}
// puts("solve");
}
int main()
{
// int n,k;
scanf("%d%d",&n,&k);
for(int x,y,z,i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x+1,y+1,z);//点编号是从0开始的
add(y+1,x+1,z);
}
// v[0]=0;
for(int i=1;i<=k;i++)
{
v[i]=inf;
}
root=0;
f[0]=n;
// dfs(1);
ms=n;
getroot(1,0);
// printf("%d\n",root);
solve(root);
if(ans==inf) printf("-1\n");
else printf("%d\n",ans);
return 0;
}

    小结:一定要注意dis数组和deep数组分别的含义。然后主函数里所有函数的fa都是0,因为是递归处理,但是其实将fa改成pos也没有问题,因为pos节点已经当过重心、被删除了。

[bzoj2599][IOI2011]Race_树上点分治的更多相关文章

  1. bzoj2599: [IOI2011]Race(点分治)

    写了四五道点分治的题目了,算是比较理解点分治是什么东西了吧= = 点分治主要用来解决点对之间的问题的,比如距离为不大于K的点有多少对. 这道题要求距离等于K的点对中连接两点的最小边数. 那么其实道理是 ...

  2. [luogu4149][bzoj2599][IOI2011]Race【点分治】

    题目描述 给一棵树,每条边有权.求一条简单路径,权值和等于 K,且边的数量最小. 题解 比较明显需要用到点分治,我们定义\(d\)数组表示当前节点到根节点\(rt\)之间有多少个节点,也可以表示有多少 ...

  3. 2019.01.09 bzoj2599: [IOI2011]Race(点分治)

    传送门 题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. 思路: 考虑点分治如何合并. 我们利用树形dpdpdp求树的直径的方法,边dfsdfsdfs子树边统计答案即可. 代码: ...

  4. BZOJ2599 [IOI2011]Race 【点分治】

    题目 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 输入格式 第一行 两个整数 n, k 第二..n行 每行三个整 ...

  5. BZOJ_2599_[IOI2011]Race_点分治

    BZOJ_2599_[IOI2011]Race_点分治 Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 10 ...

  6. [bzoj2599][IOI2011]Race——点分治

    Brief Description 给定一棵带权树,你需要找到一个点对,他们之间的距离为k,且路径中间的边的个数最少. Algorithm Analyse 我们考虑点分治. 对于子树,我们递归处理,所 ...

  7. 【BZOJ2599】Race(点分治)

    [BZOJ2599]Race(点分治) 题面 BZOJ权限题,洛谷 题解 好久没写过点分治了... 在ppl的帮助下终于想起来了 orz ppl 首先回忆一下怎么求有没有正好是\(K\)的路径 维护一 ...

  8. codeforces 161D Distance in Tree 树上点分治

    链接:https://codeforces.com/contest/161/problem/D 题意:给一个树,求距离恰好为$k$的点对是多少 题解:对于一个树,距离为$k$的点对要么经过根节点,要么 ...

  9. POJ 1741 Tree 树上点分治

    题目链接:http://poj.org/problem?id=1741 题意: 给定一棵包含$n$个点的带边权树,求距离小于等于K的点对数量 题解: 显然,枚举所有点的子树可以获得答案,但是朴素发$O ...

随机推荐

  1. 【WIP】Bootstrap modal

    创建: 2017/09/28   更新: 2017/10/14 标题加上[WIP]

  2. Sublime Text3 配置 Lua5.3.5开发环境

    所需软件 Sublime Text3 Lua5.3.5 配置过程 解压Lua5.3.5包 官方下载的包内是需要makefile安装的(博主Win10下暂为实现),此处提供自动配置完毕的包:Lua5.3 ...

  3. Akka源码分析-Router

    akak中还有一个比较重要的概念,那就是Router(路由).路由的概念,相信大家都不陌生,在akka中,它就是其他actors的一个代理,会把消息按照路由规则,分发给指定的actor.我一般喜欢把R ...

  4. Elasticsearch索引的操作,利用kibana(如何创建/删除一个es的索引?)

    我们已经通过索引一篇文档创建了一个新的索引 .这个索引采用的是默认的配置,新的字段通过动态映射的方式被添加到类型映射.现在我们需要对这个建立索引的过程做更多的控制:我们想要确保这个索引有数量适中的主分 ...

  5. 321 Create Maximum Number 拼接最大数

    已知长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,直观地表示两个自然数各位上的数字.现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要求从同一个数组中 ...

  6. 生成错误:对路径".dll"的访问被拒绝

    第一步:检查dll所在的目录的访问权限,右键文件夹>属性>安全>设置添加EveryOne用户并将完全控制的权限赋给它. 如果问题还没有解决,请不要一遍遍的重启,看第二步: 第二步:右 ...

  7. Mongo优化笔记

    最近MongoDb服务器负载比较高,容易出问题,这里把优化的方式整理一下. 1.由于各个项目组共用一个mongo实例,所以一个项目组的问题会影响到别的项目组,所以需要把各个项目的数据从一个实例中剥离出 ...

  8. 如何将工程推到github上

    首先,读一下这个 Git-Pro中文版 步骤: 在本地文件系统中 git init 在github中新建项目(光新建就行了) 然后,出现下面这张图,打开sourceTree,按照上面的操作进行就行了. ...

  9. Review:Microbiota, metagenome, microbiome傻傻分不清

    Microbiota 微生物群   微生物群是指研究动植物体上共生或病理的微生物生态群体.微生物群包括细菌.古菌.原生动物.真菌和病毒.研究表明其在宿主的免疫.代谢和激素等方面非常重要.近义词Micr ...

  10. vue项目中使用百度地图的方法

    1.在百度地图申请密钥: http://lbsyun.baidu.com/  将 <script type="text/javascript" src="http: ...