【点分治】BZOJ 2599:[IOI2011]Race
2016-02-03 08:43
302 查看
BZOJ 2599:[IOI2011]Race
Description
给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.Input
第一行 两个整数 n, k第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)
Output
一个整数 表示最小边数量 如果不存在这样的路径 输出-1Sample Input
4 30 1 1
1 2 2
1 3 4
Sample Output
2HINT
N<=200000 K<=1000000Solution
t[x]表示以当前root为根,离根距离为x的点经过的最小边数.然后每次找一颗子树cal,然后再把它add进去
最后清空那里听hzwer说好像这样比memset要快?
Code
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define maxn 2000001 struct edge{ int to,lst,c; }e[maxn*2]; int last[maxn],tot,vis[maxn],son[maxn],size,root,d[maxn],t[maxn],m,ans,f[maxn]; long long dis[maxn]; inline int in() { int x=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar(); return x; } void Add(int u,int v,int c) { e[++tot]=(edge){v,last[u],c};last[u]=tot; e[++tot]=(edge){u,last[v],c};last[v]=tot; } void findroot(int poi,int lst) { son[poi]=1;f[poi]=0; for(int i=last[poi];i;i=e[i].lst) if(e[i].to!=lst && !vis[e[i].to]) { findroot(e[i].to,poi); son[poi]+=son[e[i].to]; f[poi]=max(f[poi],son[e[i].to]); } f[poi]=max(f[poi],size-son[poi]); if(f[poi]<f[root])root=poi; } void cal(int poi,int lst) { if(dis[poi]<=m)ans=min(ans,t[m-dis[poi]]+d[poi]); for(int i=last[poi];i;i=e[i].lst) if(e[i].to!=lst && !vis[e[i].to]) { d[e[i].to]=d[poi]+1; dis[e[i].to]=dis[poi]+e[i].c; cal(e[i].to,poi); } } void add(int poi,int lst,int flag) { if(dis[poi]<=m) { if(!flag)t[dis[poi]]=min(t[dis[poi]],d[poi]); else t[dis[poi]]=99999999; } for(int i=last[poi];i;i=e[i].lst) if(e[i].to!=lst && !vis[e[i].to]) add(e[i].to,poi,flag); } void work(int poi) { vis[poi]=1;t[0]=0; for(int i=last[poi];i;i=e[i].lst) if(!vis[e[i].to]) { d[e[i].to]=1,dis[e[i].to]=e[i].c; cal(e[i].to,0); add(e[i].to,0,0); } for(int i=last[poi];i;i=e[i].lst) if(!vis[e[i].to]) add(e[i].to,0,1); for(int i=last[poi];i;i=e[i].lst) if(!vis[e[i].to]) { root=0;size=son[e[i].to]; findroot(e[i].to,poi); work(root); } } int main() { freopen("2599.in","r",stdin); int n; n=in(),m=in();ans=n+1; for(int i=1;i<=m;i++)t[i]=n; for(int i=1;i<n;i++) { int u=in()+1,v=in()+1,c=in(); Add(u,v,c); } size=n;f[0]=n; root=0; findroot(1,0); work(root); if(ans==n+1)printf("-1"); else printf("%d",ans); return 0; }
相关文章推荐
- android: 广播机制
- 8.11 小结
- 8.10 组织行为
- KMP模板
- Cheatsheet: 2016 01.01 ~ 01.31
- 8.9.2 嵌套分析函数
- 【Leetcode】Longest palindrome substring
- 8.9.1 动态SQL
- 8.8.2 谓语
- 8.8.1 执行计划
- Java手动创建一个内存泄漏的程序
- 数据结构图文解析之:队列详解与C++模板实现
- 8.6.1 例子:使用First_value来计算最大值
- 2016太原网络营销师郭文军剖析支付宝#集褔#的原因
- 8.6 First_value和Last_value
- 机房个人版——sqlhelp那点事
- Aqua Data Studio 查询结果中文乱码
- 8.5.2 例1:从前一行中返回一个值
- 8.5.1 语法和排序
- 每天一个linux命令(2):cd命令