• 【BZOJ2599】[IOI2011]Race 树的点分治


    【BZOJ2599】[IOI2011]Race

    Description

    给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000

    Input

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

    Output

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

    Sample Input

    4 3
    0 1 1
    1 2 2
    1 3 4

    Sample Output

    2

    题解:本题大部分代码都与POJ1741那道模板题相同,只不过是calc函数里有些不一样

    如果我们想计算一棵子树里的答案,仍然是先按照每个点到根的距离排序,然后用双指针法算出长度=m的路径,那么问题来了,我们怎样将答案中的非简单路径去掉呢?

    由于我们最终要求的是经过边最少的长度=m的简单路径,那么我们可以用ans[i]保存经过i条边的路径数,然后在calc的时候直接修改ans就行了

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn=200010;
    int to[maxn<<1],next[maxn<<1],val[maxn<<1],dep[maxn],s[maxn],head[maxn],siz[maxn];
    int vis[maxn],ans[maxn],p[maxn];
    int n,m,tot,cnt,root,maxx;
    
    bool cmp(int a,int b)
    {
    	return s[a]<s[b];
    }
    void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    }
    void getroot(int x,int fa)
    {
    	int i,mx=0;
    	siz[x]=1;
    	for(i=head[x];i!=-1;i=next[i])
    	{
    		if(to[i]==fa||vis[to[i]])	continue;
    		getroot(to[i],x);
    		siz[x]+=siz[to[i]];
    		mx=max(mx,siz[to[i]]);
    	}
    	mx=max(mx,tot-siz[x]);
    	if(maxx>mx)	root=x,maxx=mx;
    }
    void getdep(int x,int fa)
    {
    	p[++p[0]]=x;
    	for(int i=head[x];i!=-1;i=next[i])
    	{
    		if(to[i]==fa||vis[to[i]])	continue;
    		s[to[i]]=s[x]+val[i],dep[to[i]]=dep[x]+1;
    		getdep(to[i],x);
    	}
    }
    void calc(int x,int flag)
    {
    	p[0]=0,getdep(x,0);
    	sort(p+1,p+p[0]+1,cmp);
    	int l=1,r=p[0],i;
    	for(;l<r;l++)
    	{
    		while(l<r&&s[p[l]]+s[p[r]]>m)	r--;
    		for(i=r;i>l&&s[p[l]]+s[p[i]]==m;i--)	ans[dep[p[l]]+dep[p[i]]]+=flag;
    	}
    }
    void dfs(int x)
    {
    	vis[x]=1;
    	s[x]=dep[x]=0,calc(x,1);
    	for(int i=head[x];i!=-1;i=next[i])
    	{
    		if(vis[to[i]])	continue;
    		s[to[i]]=val[i],dep[to[i]]=1,calc(to[i],-1);
    		maxx=1<<30,tot=siz[to[i]],getroot(to[i],x);
    		dfs(root);
    	}
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int i,a,b,c;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<n;i++)
    	{
    		scanf("%d%d%d",&a,&b,&c),a++,b++;
    		add(a,b,c),add(b,a,c);
    	}
    	maxx=1<<30;
    	getroot(1,0);
    	dfs(1);
    	for(i=1;i<=n;i++)
    	{
    		if(ans[i])
    		{
    			printf("%d
    ",i);
    			return 0;
    		}
    	}
    	printf("-1");
    	return 0;
    }

     

  • 相关阅读:
    克隆节点及添加属性节点
    元素属性的添加删除(原生js)
    清浮动方法
    css样式获取及兼容性(原生js)
    js基础---数据类型转换
    js基础---数字日期及运算
    js基础---object对象
    input询问键盘输入超时自动跳过选择默认值
    xpath定位
    selenium报错问题解决方法
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6641635.html
Copyright © 2020-2023  润新知