zoukankan      html  css  js  c++  java
  • bzoj2599 [IOI2011]Race

    Description

    给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.

    Input

    第一行 两个整数 n, k
    第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)

    Output

    一个整数 表示最小边数量 如果不存在这样的路径 输出-1

    Sample Input

    4 3
    0 1 1
    1 2 2
    1 3 4

    Sample Output

    2
     
    第一次写点分治……要讲详细点
    把所有可行解分成过当前点和不过当前点两种情况,过当前点的直接处理,不过当前点的就递归到子树做,然后一样分为过当前点和不过当前点……
    然后要找个树的重心,就是把无根树建成以x为根的有根树之后,使子树的儿子个数最大值最小的x
    对于这题,用t[k]表示当前子树中到根的路径权值和为k的最短边。换而言之就是权值和为k又经过最少边
    然后就可以分治搞掉
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<deque>
    #include<set>
    #include<map>
    #include<ctime>
    #define LL long long
    #define inf 0x7ffffff
    #define pa pair<int,int>
    #define pi 3.1415926535897932384626433832795028841971
    #define N 200010
    using namespace std;
    inline LL read()
    {
        LL x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,k,cnt,sum,root,ans;
    struct edge{
    	int to,next,v;
    }e[2*N];
    int head[N];
    int f[N];
    int son[N];
    int vis[N];
    int dep[N];
    int dist[N];
    int t[1000010];
    inline void ins(int u,int v,int w)
    {
    	e[++cnt].to=v;
    	e[cnt].v=w;
    	e[cnt].next=head[u];
    	head[u]=cnt;
    }
    inline void insert(int u,int v,int w)
    {
    	ins(u,v,w);
    	ins(v,u,w);
    }
    inline void getroot(int x,int fa)
    {
    	son[x]=1;f[x]=0;
    	for (int i=head[x];i;i=e[i].next)
    	  if (e[i].to!=fa&&!vis[e[i].to])
    	  {
    	  	getroot(e[i].to,x);
    	  	son[x]+=son[e[i].to];
    	  	f[x]=max(f[x],son[e[i].to]);
    	  }
    	f[x]=max(f[x],sum-son[x]);
    	if (f[x]<f[root])root=x;
    }
    inline void dfs(int x,int fa)
    {
    	if(dist[x]<=k)ans=min(ans,dep[x]+t[k-dist[x]]);
    	for (int i=head[x];i;i=e[i].next)
    	  if (fa!=e[i].to&&!vis[e[i].to])
    	  {
    	  	dep[e[i].to]=dep[x]+1;
    	  	dist[e[i].to]=dist[x]+e[i].v;
    	  	dfs(e[i].to,x);
    	  }
    }
    inline void add(int x,int fa,int opr)
    {
    	if (dist[x]<=k)
    	{
    		if (opr==1)t[dist[x]]=min(t[dist[x]],dep[x]);
    		else t[dist[x]]=inf;
    	}
    	for (int i=head[x];i;i=e[i].next)
    	  if (e[i].to!=fa&&!vis[e[i].to])
    	    add(e[i].to,x,opr);
    }
    inline void work(int x)
    {
    	vis[x]=1;t[0]=0;
    	for (int i=head[x];i;i=e[i].next)
    	  if (!vis[e[i].to])
    	  {
    	  	dep[e[i].to]=1;dist[e[i].to]=e[i].v;
    	  	dfs(e[i].to,0);
    	  	add(e[i].to,0,1);
    	  }
    	for (int i=head[x];i;i=e[i].next)
    	  if (!vis[e[i].to])add(e[i].to,0,0);
    	for (int i=head[x];i;i=e[i].next)
    	  if (!vis[e[i].to])
    	  {
    		root=0;sum=son[e[i].to];
    		getroot(e[i].to,0);
    		work(root);
    	  }
    }
    int main()
    {
    	n=read();k=read();
    	for (int i=1;i<=k;i++)t[i]=n;
    	for(int i=1;i<n;i++)
    	{
    		int x=read()+1,y=read()+1,z=read();
    		insert(x,y,z);
    	}
    	ans=sum=f[0]=n;
    	getroot(1,0);
    	work(root);
    	if (ans==n)printf("-1
    ");
    	else printf("%d
    ",ans);
    	return 0;
    }
    

      

    ——by zhber,转载请注明来源
  • 相关阅读:
    突然又想起了这首诗
    安装使用Androidx86打造快速流畅的Aandroid开发环境!
    解决电脑没插网线虚拟机无法桥接到主机
    使用WordPress更新通知服务,让搜索引擎知道你更新了,加快收录。
    php+apache+mysql环境配置时apache服务不能开启的解决
    WordPress备份的七种办法
    怎么在网站中正确使用JQuery代码
    如何让自己的博客在各搜索引擎中被搜索出来与快速收录
    轻松查看文件被哪个进程使用
    解密QQ非会员漫游聊天记录
  • 原文地址:https://www.cnblogs.com/zhber/p/4150518.html
Copyright © 2011-2022 走看看