题目描述

给一棵树,每条边有权。求一条简单路径,权值和等于 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【点分治】的更多相关文章

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

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

  2. BZOJ2599:[IOI2011]Race(点分治)

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

  3. 【BZOJ-2599】Race 点分治

    2599: [IOI2011]Race Time Limit: 70 Sec  Memory Limit: 128 MBSubmit: 2590  Solved: 769[Submit][Status ...

  4. BZOJ 2599: [IOI2011]Race( 点分治 )

    数据范围是N:20w, K100w. 点分治, 我们只需考虑经过当前树根的方案. K最大只有100w, 直接开个数组CNT[x]表示与当前树根距离为x的最少边数, 然后就可以对根的子树依次dfs并更新 ...

  5. [IOI2011]Race 点分治

    [IOI2011]Race LG传送门 点分治板子题. 直接点分治统计,统计的时候开个桶维护下就好了. 注(tiao)意(le)细(hen)节(jiu). #include<cstdio> ...

  6. bzoj2599/luogu4149 [IOI2011]Race (点分治)

    点分治.WA了一万年. 重点就是统计答案的方法 做法一(洛谷AC bzojWA 自测WA): 做点x时记到x距离为k的边数最小值为dis[k],然后对每一对有值的dis[i]和dis[K-i],给an ...

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

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

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

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

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

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

随机推荐

  1. MySQL的binlog及关闭方法

    如何关闭MySQL日志,删除mysql-bin.0000*日志文件 - VPS侦探https://www.vpser.net/manage/delete-mysql-mysql-bin-0000-lo ...

  2. CentOS下配置SS5(SOCKS5)代理服务器

    方案:使用开源的SS5( Socks Server 5 ) 官网:http://ss5.sourceforge.net/ (点击左侧的Software在右侧的Server处进入下载地址) CentOs ...

  3. Java Integer 与 int 深刻理解

    今天在做Object 自动转为Integer 类型之后的判断,遇到一个不理解的点,当数值超过127之后,两个数值相同的Object 对象用 == 判断的结果是false. Object a = 128 ...

  4. win10查看无线密码

  5. Python 构建工具 buildout 的介绍与使用

    来到了新公司上班,首先就是得把自己的环境给搭起来.知乎使用了buildout作为python项目的构建工具. 那么什么是 buildout ? buildout的是一款自动化构建工具.由Zope团队开 ...

  6. NFS配置与搭建

    参考: Linux下NFS服务器的搭建与配置 https://www.cnblogs.com/liuyisai/p/5992511.html http://blog.51cto.com/hongten ...

  7. 老男孩python学习自修第九天【yield生成器】

    1.如果在一个方法中有yield关键字则该方法返回的是一个生成器对象 2.对生成器对象进行操作必须进行迭代或循环处理 例如: yield_test.py #!/usr/bin/env python # ...

  8. ajax查看详细返回信息

    查看详细成功返回信息: success : function(data, textStatus, jqXHR) { console.log(data); console.log(textStatus) ...

  9. Java多线程之静态代理

    package org.study2.javabase.ThreadsDemo.staticproxy; /** * @Date:2018-09-18 静态代理 设计模式 * 1.真实角色 * 2.代 ...

  10. C# json解析

    json格式数 [{ , , , "ItemCode": "UBAC11211OF-A54", "basicName_bg": " ...