[luogu4149][bzoj2599][IOI2011]Race【点分治】
题目描述
给一棵树,每条边有权。求一条简单路径,权值和等于 K,且边的数量最小。
题解
比较明显需要用到点分治,我们定义\(d\)数组表示当前节点到根节点\(rt\)之间有多少个节点,也可以表示有多少条边,然后我们在定义\(dis\)表示当前节点到根节点\(rt\)的距离,那么我们就可以得到\(ans=min(ans,d[u]+t[k-dis[u]])\),这个方程还是比较容易的。
但是这道题目不满足状态可减性,说的明白一点就是答案和答案之间无法相减,那么点分治的容斥原理处理就可以变成将原来没有访问过得节点的答案都变成\(inf\),这样我们算的时候就不会把这些重复部分算多次。
ac代码
# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x3f3f3f3f)/3
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
inline int gi(){
int w=0,x=0;char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return w?-x:x;
}
# define N 1000005
struct edge{
int to,nt,w;
}E[N<<1];
int H[N],cnt,n,k,rt,sum,mx,sz[N],ans,mxs[N],d[N],dis[N],t[N];
bool vis[N];
void addedge(int u,int v,int w){
E[++cnt]=(edge){v,H[u],w}; H[u]=cnt;
}
void get_root(int u,int fa){
sz[u]=1; mxs[u]=-1;
for (int e=H[u];e;e=E[e].nt){
if (vis[E[e].to]||E[e].to==fa) continue;
get_root(E[e].to,u);
sz[u]+=sz[E[e].to];
mxs[u]=max(mxs[u],sz[E[e].to]);
}
mxs[u]=max(sum-sz[u],mxs[u]);
if (mxs[u]<mx) mx=mxs[u],rt=u;
}
void calc(int u,int fa){
if (dis[u]<=k) ans=min(ans,d[u]+t[k-dis[u]]);//如果当前的距离是小于k的,那么就说明可能可以更新答案
for (int e=H[u];e;e=E[e].nt){
if (E[e].to==fa||vis[E[e].to]) continue;
d[E[e].to]=d[u]+1;
dis[E[e].to]=dis[u]+E[e].w;
calc(E[e].to,u);
}
}
void update(int u,int fa,bool fg){//更新边上的答案
if (dis[u]<=k) {
if (fg) t[dis[u]]=min(t[dis[u]],d[u]);//如果是访问过得,那么就直接更新
else t[dis[u]]=inf;//如果没有访问过,那么就赋值成inf,防止重复
}
for (int e=H[u];e;e=E[e].nt){//继续更新边上的答案
if (E[e].to==fa||vis[E[e].to]) continue;
update(E[e].to,u,fg);
}
}
void divide(int u){
vis[u]=1; t[0]=0;
for (int e=H[u];e;e=E[e].nt){
if (vis[E[e].to]) continue;
d[E[e].to]=1; dis[E[e].to]=E[e].w; calc(E[e].to,-1); update(E[e].to,-1,1);//计算全局的答案
}
for (int e=H[u];e;e=E[e].nt){//将所有没有访问过得答案还原,防止答案重复
if (!vis[E[e].to]) update(E[e].to,-1,0);
}
for (int e=H[u];e;e=E[e].nt){//递归分治
if (vis[E[e].to]) continue;
mx=inf; sum=sz[E[e].to]; rt=0; get_root(E[e].to,-1); divide(rt);
}
}
int main(){
ms(t,inf); n=gi(),k=gi();
for (int i=2;i<=n;i++){
int u=gi(),v=gi(),w=gi();
u++,v++;
addedge(u,v,w); addedge(v,u,w);
}
sum=n; mx=inf; rt=-1; get_root(1,-1);
ans=inf; divide(rt);
printf("%d\n",(ans==inf)?(-1):(ans));
return 0;
}
[luogu4149][bzoj2599][IOI2011]Race【点分治】的更多相关文章
- [bzoj2599][IOI2011]Race——点分治
Brief Description 给定一棵带权树,你需要找到一个点对,他们之间的距离为k,且路径中间的边的个数最少. Algorithm Analyse 我们考虑点分治. 对于子树,我们递归处理,所 ...
- BZOJ2599:[IOI2011]Race(点分治)
Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 Input 第一行 两个整数 n, k 第二 ...
- 【BZOJ-2599】Race 点分治
2599: [IOI2011]Race Time Limit: 70 Sec Memory Limit: 128 MBSubmit: 2590 Solved: 769[Submit][Status ...
- BZOJ 2599: [IOI2011]Race( 点分治 )
数据范围是N:20w, K100w. 点分治, 我们只需考虑经过当前树根的方案. K最大只有100w, 直接开个数组CNT[x]表示与当前树根距离为x的最少边数, 然后就可以对根的子树依次dfs并更新 ...
- [IOI2011]Race 点分治
[IOI2011]Race LG传送门 点分治板子题. 直接点分治统计,统计的时候开个桶维护下就好了. 注(tiao)意(le)细(hen)节(jiu). #include<cstdio> ...
- bzoj2599/luogu4149 [IOI2011]Race (点分治)
点分治.WA了一万年. 重点就是统计答案的方法 做法一(洛谷AC bzojWA 自测WA): 做点x时记到x距离为k的边数最小值为dis[k],然后对每一对有值的dis[i]和dis[K-i],给an ...
- bzoj2599: [IOI2011]Race(点分治)
写了四五道点分治的题目了,算是比较理解点分治是什么东西了吧= = 点分治主要用来解决点对之间的问题的,比如距离为不大于K的点有多少对. 这道题要求距离等于K的点对中连接两点的最小边数. 那么其实道理是 ...
- 2019.01.09 bzoj2599: [IOI2011]Race(点分治)
传送门 题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. 思路: 考虑点分治如何合并. 我们利用树形dpdpdp求树的直径的方法,边dfsdfsdfs子树边统计答案即可. 代码: ...
- BZOJ2599 [IOI2011]Race 【点分治】
题目 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 输入格式 第一行 两个整数 n, k 第二..n行 每行三个整 ...
随机推荐
- pip 安装 和 卸载 django
1. 在dos命令行中输入 pip 如下命令进行安装: 安装最新的版本的 Django 命令如下: pip install django 安装 指定版本的 Django 命令如下: pip insta ...
- Python之操作Excel
使用之前先导入三个模块: import xlwt #只能写Excel import xlrd #只能读Excel import xlutils #修改Excel,在原来的基础上修改 一.写EXCEL ...
- C#设计模式之3:观察者模式
C#中已经实现了观察者模式,那就是事件,事件封装了委托,使得委托的封装性更好,在类的内部定义事件,然后在客户端对事件进行注册: public class Subject { public event ...
- css3新属性box-orient
前言 box-orient属性经常与display:box属性结合使用 div { width:350px; height:100px; border:1px solid black; /* Fire ...
- Laravel5.5+ 区分前后端用户登录
Laravel 的用户认证是通过 Auth Facade 门脸实现的,手动认证可是使用 Auth::login() 或 Auth::attempt() 这两个方法实现. 以下内容纯属个人实现,也许有 ...
- object-fit 属性的用法介绍
这个要在宽,高都是100%的情况下才能提现 object-fit 属性的用法介绍 fill(不保持纵横比缩放图片,使图片完全适应) contain(保持纵横比缩放图片,使图片的长边能完全显示出来) c ...
- Eclipse在写java时的BUG
要把这个关掉
- C# Note31: 如何使用Visual Studio做单元测试
待更! 使用Visual Studio 2013进行单元测试--初级篇 带你玩转Visual Studio——单元测试(C++例)
- Flutter的scope_model使用mixin语法报错
在pubspec.yaml同级目录下创建analysis_options.yaml文件,内容: # https://www.dartlang.org/guides/language/analysis- ...
- ajax查看详细返回信息
查看详细成功返回信息: success : function(data, textStatus, jqXHR) { console.log(data); console.log(textStatus) ...