隐藏页面特效

2599: [IOI2011]Race

2599: [IOI2011]Race

Time Limit: 70 Sec  Memory Limit: 128 MB
Submit: 3088  Solved: 905
[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

HINT

 

Source

 
[Submit][Status][Discuss]

这题有点怪的点分治。。。

我的做法也比较逗,就是开一个100W的数组t,t[i]表示权值为i的路径最少边数

找到重心分成若干子树后, 得出一棵子树的所有点到根的权值和x,到根a条边,用t[k-x]+a更新答案,全部查询完后

然后再用所有a更新t[x]

这样可以保证不出现点分治中的不合法情况

把一棵树的所有子树搞完后再遍历所有子树恢复T数组,如果用memset应该会比较慢

orz hzwer!

#include<cstdio> #include<iostream> #pragma GCC optimize("O2") using namespace std; 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; } const int N=2e5+5,M=1e6+5; int n,K,tot,sum,root,ans; int t[M],head[N],son[N],f[N],dis[N],d[N]; bool vis[N]; struct node{ int v,w,next; }e[N<<1]; void ins(int x,int y,int z){ e[++tot].v=y;e[tot].w=z;e[tot].next=head[x];head[x]=tot; e[++tot].v=x;e[tot].w=z;e[tot].next=head[y];head[y]=tot; } void getroot(int x,int fa){ son[x]=1;f[x]=0; for(int i=head[x],v;i;i=e[i].next){ if(!vis[v=e[i].v]&&v!=fa){ getroot(v,x); son[x]+=son[v]; f[x]=max(f[x],son[v]); } } f[x]=max(f[x],sum-son[x]); if(f[x]<f[root]) root=x; } void cal(int x,int fa){ if(dis[x]<=K) ans=min(ans,d[x]+t[K-dis[x]]); for(int i=head[x],v;i;i=e[i].next){ if(!vis[v=e[i].v]&&v!=fa){ d[v]=d[x]+1; dis[v]=dis[x]+e[i].w; cal(v,x); } } } void add(int x,int fa,bool flag){ if(dis[x]<=K){ if(flag) t[dis[x]]=min(t[dis[x]],d[x]); else t[dis[x]]=1e9; } for(int i=head[x],v;i;i=e[i].next){ if(!vis[v=e[i].v]&&v!=fa){ add(v,x,flag); } } } void work(int x){ vis[x]=1;t[0]=0; for(int i=head[x],v;i;i=e[i].next){ if(!vis[v=e[i].v]){ d[v]=1; dis[v]=e[i].w; cal(v,0); add(v,0,1); } } for(int i=head[x],v;i;i=e[i].next){ if(!vis[v=e[i].v]){ add(v,0,0); } } for(int i=head[x],v;i;i=e[i].next){ if(!vis[v=e[i].v]){ root=0; sum=son[v]; getroot(v,0); work(root); } } } int main(){ n=read();K=read(); for(int i=1;i<=K;i++) t[i]=n; for(int i=1,x,y,z;i<n;i++){ x=read();y=read();z=read(); ins(x+1,y+1,z); } ans=sum=f[0]=n; getroot(1,0); work(root); printf("%d\n",ans!=n?ans:-1); return 0; }

 


__EOF__

本文作者shenben
本文链接https://www.cnblogs.com/shenben/p/6295976.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   神犇(shenben)  阅读(303)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示