ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CH4908 Race

2019-04-06 12:47:36  阅读:280  来源: 互联网

标签:ch int 路径 CH4908 Race rg 权值 data


题意

描述

给定一棵 N 个节点的树,每条边带有一个权值。

求一条简单路径,路径上各条边的权值和等于K,且路径包含的边的数量最少。

输入格式

第一行两个整数 N, K。
第2~N行每行三个整数x,y,z,表示一条无向边的两个端点x,y和权值z,点的编号从0开始。

输出格式

一个整数,表示最少边数量。如果不存在满足要求的路径,输出-1。

样例输入

4 3
0 1 1
1 2 2
1 3 4

样例输出

2

数据范围与约定

  • N <= 200000, K <= 1000000

来源

IOI2011

分析

训练指南的配套代码有问题,双指针绝对是错的。学习了hzwer的做法。

开一个100W的数组t,t[i]表示权值为i的路径最少边数

找到重心分成若干子树后, 得出一棵子树的所有点到根的权值和x,到根c条边,用t[k-x]+c更新答案,全部查询完后

然后再用所有c更新t[x]

这样可以保证不出现点分治中的不合法情况

把一棵树的所有子树搞完后再遍历所有子树恢复T数组,如果用memset应该会比较慢

时间复杂度\(O(n \log^2 n)\)

代码

网上好多代码,点分治递归的时候没有重新统计以重心为根的整棵树每个节点的size,按道理找出来的重心是错的,复杂度没有保证。

但是出题人根本就不会卡这种东西,所以不用写了,反而常数小。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
    while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;
typedef pair<int,int> pii;

co int N=2e5+1;
int n,k,ans,sum,root,max_size;
vector<pii> e[N];
int t[1000001],s[N],d[N],c[N],v[N];
void getroot(int x){
    v[x]=1,s[x]=1;
    int max_part=0;
    for(int i=0,y;i<e[x].size();++i){
        if(v[y=e[x][i].first]) continue;
        getroot(y);
        s[x]+=s[y],max_part=max(max_part,s[y]);
    }
    max_part=max(max_part,sum-s[x]);
    if(max_part<max_size) root=x,max_size=max_part;
    v[x]=0;
}
void cal(int x){
    v[x]=1;
    if(d[x]<=k) ans=min(ans,c[x]+t[k-d[x]]);
    for(int i=0,y;i<e[x].size();++i){
        if(v[y=e[x][i].first]) continue;
        c[y]=c[x]+1,d[y]=d[x]+e[x][i].second;
        cal(y);
    }
    v[x]=0;
}
void add(int x,int flag){
    v[x]=1;
    if(d[x]<=k){
        if(flag) t[d[x]]=min(t[d[x]],c[x]);
        else t[d[x]]=n;
    }
    for(int i=0,y;i<e[x].size();++i){
        if(v[y=e[x][i].first]) continue;
        add(y,flag);
    }
    v[x]=0;
}
void work(int x){
    v[x]=1,t[0]=0;
    for(int i=0,y;i<e[x].size();++i){
        if(v[y=e[x][i].first]) continue;
        c[y]=1,d[y]=e[x][i].second;
        cal(y),add(y,1);
    }
    for(int i=0,y;i<e[x].size();++i){
        if(v[y=e[x][i].first]) continue;
        add(y,0);
    }
    for(int i=0,y;i<e[x].size();++i){
        if(v[y=e[x][i].first]) continue;
        sum=max_size=s[y];
        getroot(y),work(root);
    }
}
int main(){
//  freopen(".in","r",stdin),freopen(".out","w",stdout);
    read(n),read(k);
    fill(t+1,t+k+1,n);
    for(int i=1,u,v,w;i<n;++i){
        read(u),read(v),read(w);
        e[++u].push_back(pii(++v,w)),e[v].push_back(pii(u,w));
    }
    ans=sum=max_size=n;
    getroot(1),work(root);
    if(ans==n) puts("-1");
    else printf("%d\n",ans);
    return 0;
}

标签:ch,int,路径,CH4908,Race,rg,权值,data
来源: https://www.cnblogs.com/autoint/p/10661411.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有