首页 > 代码库 > bzoj 2599(点分治)

bzoj 2599(点分治)

2599: [IOI2011]Race

Time Limit: 70 Sec  Memory Limit: 128 MB
Submit: 3642  Solved: 1081
[Submit][Status][Discuss]

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
 
/*开一个100W的数组t,t[i]表示权值为i的路径最少边数找到重心分成若干子树后, 得出一棵子树的所有点到根的权值和x,到根a条边,用t[k-x]+a更新答案,全部查询完后然后再用所有a更新t[x]这样可以保证不出现点分治中的不合法情况把一棵树的所有子树搞完后再遍历所有子树恢复T数组,如果用memset应该会比较慢*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define inf 1000000000#define maxn 1000005#define maxx 200005using namespace std;int n,K,cnt,sum,root,ans,x,y,z;int tot[maxn],head[maxx],son[maxx],f[maxx],dis[maxx],d[maxx];bool vis[maxx];struct edge{    int to,next,w;}e[maxx<<1];inline int read(){    int 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;}void add(int u,int v,int w){    e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].w=w;}void get_root(int now,int fa){    son[now]=1;f[now]=0;    for(int i=head[now];i;i=e[i].next)    {        int v=e[i].to;        if(v!=fa&&!vis[v])        {            get_root(v,now);            son[now]+=son[v];f[now]=max(f[now],son[v]);                    }    }    f[now]=max(f[now],sum-son[now]);    if(f[now]<f[root]) root=now;}void cal(int now,int fa){    if(dis[now]<=K) ans=min(ans,d[now]+tot[K-dis[now]]);    for(int i=head[now];i;i=e[i].next)    {        int v=e[i].to;        if(!vis[v]&&v!=fa)        {            d[v]=d[now]+1;            dis[v]=dis[now]+e[i].w;            cal(v,now);                    }    }}void updata(int now,int fa,int flag){    if(dis[now]<=K)    {        if(flag) tot[dis[now]]=min(tot[dis[now]],d[now]);        else tot[dis[now]]=inf;    }    for(int i=head[now];i;i=e[i].next)    {        int v=e[i].to;        if(!vis[v]&&v!=fa)          updata(v,now,flag);    }}void work(int now){    vis[now]=1;tot[0]=0;    for(int i=head[now];i;i=e[i].next)    {        int v=e[i].to;        if(!vis[v])        {            d[v]=1;dis[v]=e[i].w;            cal(v,0);updata(v,0,1);                }    }    for(int i=head[now];i;i=e[i].next)    {        int v=e[i].to;        if(!vis[v])          updata(v,0,0);//去掉重心之后要重新统计     }    for(int i=head[now];i;i=e[i].next)    {        int v=e[i].to;        if(!vis[v])        {            root=0;sum=son[v];            get_root(v,0);            work(root);            }    }}int main(){    n=read();K=read();    for(int i=1;i<=K;i++)tot[i]=n;    for(int i=1;i<n;i++)    {        x=read();y=read();z=read();        x++;y++;        add(x,y,z);add(y,x,z);    }    ans=sum=f[0]=n;get_root(1,0);    work(root);    if(ans!=n)printf("%d\n",ans);    else puts("-1");    return 0;}

 

bzoj 2599(点分治)