P4149 [IOI2011]Race 点分治

  题意:给定一棵有边权的树  和一个k    问最少多少边(连续)的长度和为k   

 

解法一(也是我一开始的写法)
遍历所有的边  并且给每个边设置一个标记属于某课子树 然后用lowerbound和upperbound找到满足的边 遍历一遍统计答案  用了4s

 

解法二(只用2s)

边数太多的时候上面的算法复杂度接近 n^2logn QAQ

可以做成3n的 并且每一棵每一棵子树得统计答案和更新子树情况 (先统计  后更新)   就可以避免统计的边不是最短路的情况

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//
const int N=2e5+10;
int n,m,cnt,d[N],head[N],pos,siz[N],sum,x,y,z,ans,vis[N],root,maxson[N],k,temp[N*10];
struct Edge{int to,nex,v;}edge[N<<1];
void add(int a,int b,int c){edge[++pos]=(Edge){b,head[a],c};head[a]=pos;}
struct bian
{
    int num,v,belong;
    bool operator <(const bian &b)const{return v<b.v;}
}s[N];
void getroot(int x,int fa)
{    
    siz[x]=1;maxson[x]=0;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v]||v==fa)continue;
        getroot(v,x);siz[x]+=siz[v];
        maxson[x]=max(maxson[x],siz[v]);
    }
    maxson[x]=max(maxson[x],sum-siz[x]);
    if(maxson[x]<maxson[root])root=x;
}
void getdis(int x,int fa,int val,int num)
{    
    if(val>k)return ;
    temp[val]=min(temp[val],num);
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v]||v==fa)continue;
        getdis(v,x,val+edge[i].v,num+1);
    }
}
void init(int x,int fa,int val)
{
    if(val>k)return ;
    temp[val]=1e9 ;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v]||v==fa)continue;
        init(v,x,edge[i].v+val);
    }
}
void upans(int x,int fa,int val,int num)
{
    if(val>k)return ;
    ans=min(ans,temp[k-val]+num);
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v]||v==fa)continue;
        upans(v,x,val+edge[i].v,num+1);
    }
}
void calc(int x)
{    
    temp[0]=0;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v])continue;
        upans(v,x,edge[i].v,1);
        getdis(v,x,edge[i].v,1);
    }
    init(x,0,0);
}
void solve(int x)
{    
    vis[x]=1;
    calc(x);
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v])continue;
        root=0;sum=siz[v];
        getroot(v,x);
        solve(root);
    }
}
int main()
{    
    scanf("%d%d",&n,&k);
    rep(i,1,n-1)
    scanf("%d%d%d",&x,&y,&z),x++,y++,add(x,y,z),add(y,x,z);
    rep(i,0,k)temp[i]=1e9;
    ans=1e9;
    sum=maxson[0]=n;
    root=0;
    getroot(1,0);

    solve(root);
    if(ans==1e9)printf("-1\n");
    else printf("%d",ans);
}
View Code

 

转载于:https://www.cnblogs.com/bxd123/p/11545270.html

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值