bzoj2599

2599: [IOI2011]Race

Time Limit: 70 Sec  Memory Limit: 128 MB
Submit: 2476  Solved: 733
[Submit][Status][Discuss]

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

HINT

 

Source

 

 题解:
  随便点分治,用一个ans[i]代表u,v距离为k,边数为i的点对个数,那么答案就为i (ans[i]>0 && i 最小);
  怎么求ans? 自己yy一下吧
代码:
  
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define N 200100  
using namespace std;
int tot,n,m,all,k,root,sum;
int pre[N*2],v[N*2],val[N*2],now[N],size[N],ans[N],f[N];
bool vis[N];
struct data{int val,size;
}d[N],da[N];
bool cmp(data a,data b)
{
    return a.val<b.val;
}
int read()
{
    int x=0; char ch; bool bo=1;
    while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') bo=0;
    while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9');
    if (!bo) return -x; return x;
}
void ins(int a,int b,int c)
{
    ++tot; pre[tot]=now[a]; now[a]=tot; v[tot]=b; val[tot]=c;
}
void getroot(int u,int fa)
{
    size[u]=1; f[u]=0;
    for (int p=now[u]; p; p=pre[p])
    {
        int son=v[p];
        if (vis[son]||son==fa) continue;
        getroot(son,u);
        size[u]+=size[son];
        f[u]=max(f[u],size[son]);
    }
    f[u]=max(f[u],all-size[u]);
    if (f[u]<f[root]) root=u;
}
void getarray(int u,int fa)
{
    for (int p=now[u]; p; p=pre[p])
    {
        int son=v[p];
        if (son==fa||vis[son]) continue;
        da[++sum].val=d[son].val=d[u].val+val[p]; 
        da[sum].size=d[son].size=d[u].size+1;
        getarray(son,u);
    }
    
}
void calc(int u,int value, int f)
{
    d[u].val=value; if (f==1) d[u].size=0; else d[u].size=1; 
    sum=0; da[++sum].val=value; da[sum].size=d[u].size;
    getarray(u,0);
    sort(da+1,da+1+sum,cmp);
    for (int i=1,j=sum; i<=j; i++)
    {
        while (j>i && da[j].val+da[i].val>k) j--;
        for (int p=j; da[i].val+da[p].val==k ;p--)ans[da[p].size+da[i].size]+=f;
    }
}
void solve(int u)
{
    vis[u]=1; calc(u,0,1);
    for    (int p=now[u]; p; p=pre[p])
    {
        int son=v[p];
        if (vis[son]) continue;
        calc(son,val[p],-1);
        all=size[son]; 
        root=0; getroot(son,0);
        solve(root);
    }
}
int main()
{
    n=read(); k=read();
    for (int i=1; i<n; i++)
    {
        int u=read()+1,v=read()+1,value=read();
        ins(u,v,value); ins(v,u,value);
    }
    all=n; f[root=0]=n; getroot(1,0); 
    solve(root);
    for (int i=1; i<n; i++)
    {
        if (ans[i]) 
        {
            printf("%d\n",i);
            return 0;
        }
    }
    printf("-1\n"); return 0;
} 
View Code

 

posted @ 2016-05-07 20:38  ACist  阅读(186)  评论(0编辑  收藏  举报