BZOJ_2599_[IOI2011]Race_点分治
BZOJ_2599_[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
0 1 1
1 2 2
1 3 4
Sample Output
2
点分治。开个桶记录一下长度为x的路径最小的深度。
如何去重?我们开一个辅助桶存一下根的当前儿子的子树内的贡献。
保证每次查的时候用的是其他儿子的子树的路径。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 200050 #define inf 100000000 int head[N],to[N<<1],nxt[N<<1],cnt,val[N<<1]; int root,sum,siz[N],f[N],g[1000050],d[N],n,k,ans,dep[N],tmp[1000050],a[N],b[N]; bool used[N]; inline void add( int u, int v, int w) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w; } void get_root( int x, int y) { siz[x]=1; f[x]=0; int i; for (i=head[x];i;i=nxt[i]) if (to[i]!=y&&!used[to[i]]) { get_root(to[i],x); siz[x]+=siz[to[i]]; f[x]=max(f[x],siz[to[i]]); } f[x]=max(f[x],sum-siz[x]); if (f[x]<f[root]) root=x; } void get_dep( int x, int y) { b[++b[0]]=x; a[++a[0]]=x; siz[x]=1; dep[x]=dep[y]+1; //printf("x=%d dep[x]=%d\n",x,dep[x]); if (d[x]<=k) { ans=min(ans,g[k-d[x]]+dep[x]-2); tmp[d[x]]=min(tmp[d[x]],dep[x]); } int i; for (i=head[x];i;i=nxt[i]) if (to[i]!=y&&!used[to[i]]) { d[to[i]]=d[x]+val[i]; get_dep(to[i],x); siz[x]+=siz[to[i]]; } } void work( int x) { g[0]=1; used[x]=1; d[x]=0; int i,j; b[0]=0; siz[x]=1; dep[x]=1; for (i=head[x];i;i=nxt[i]) if (!used[to[i]]) { a[0]=0; d[to[i]]=val[i]; get_dep(to[i],x); siz[x]+=siz[to[i]]; for (j=1;j<=a[0];j++) if (d[a[j]]<=k) { g[d[a[j]]]=min(g[d[a[j]]],tmp[d[a[j]]]); } for (j=1;j<=a[0];j++) if (d[a[j]]<=k) tmp[d[a[j]]]=inf; } for (i=1;i<=b[0];i++) if (d[b[i]]<=k) { g[d[b[i]]]=tmp[d[b[i]]]=inf; } g[0]=tmp[0]=inf; for (i=head[x];i;i=nxt[i]) if (!used[to[i]]) { root=0; sum=siz[to[i]]; get_root(to[i],0); work(root); } } int main() { scanf ( "%d%d" ,&n,&k); int i,x,y,z; for (i=0;i<=k;i++) g[i]=tmp[i]=inf; for (i=1;i<n;i++) { scanf ( "%d%d%d" ,&x,&y,&z); x++;y++; add(x,y,z);add(y,x,z); } sum=n; f[0]=inf; ans=1<<30; root=0; get_root(1,0); work(root); printf ( "%d\n" ,ans>n?-1:ans); } |
标签:
点分治
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
· 用 DeepSeek 给对象做个网站,她一定感动坏了
· .NET 8.0 + Linux 香橙派,实现高效的 IoT 数据采集与控制解决方案
· .NET中 泛型 + 依赖注入 的实现与应用