首页 > 代码库 > bzoj 2599(点分治)
bzoj 2599(点分治)
2599: [IOI2011]Race
Time Limit: 70 Sec Memory Limit: 128 MBSubmit: 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
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(点分治)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。