2599: [IOI2011]Race
Time Limit: 70 Sec Memory Limit: 128 MBSubmit: 3934 Solved: 1163
[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
考虑点分治,每次对子树进行dfs求出子树中每个点到根的距离并记在dis[i]中,步数记在b[i]中。
同时我们开一个桶tot,记录这颗子树之前的子树中所有dis中步数的最小值。
开一个v的桶记录此时tot桶中记录的数是否为以当前u为根更新的答案。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<algorithm> 6 using namespace std; 7 struct data { 8 int to,next,val; 9 }e[400005]; 10 int head[200005],cnt; 11 bool vis[200005]; 12 void add(int u,int v,int val) {e[cnt].to=v;e[cnt].next=head[u];e[cnt].val=val;head[u]=cnt++;} 13 int son[200005],f[200005],root,sum; 14 int b[200005],dis[200005],tot[1000005]; 15 int n,k; 16 int ans=0; 17 int num; 18 int v[1000005]; 19 int tt=0; 20 void findroot(int x,int fa) { 21 son[x]=1;f[x]=0; 22 for(int i=head[x];i>=0;i=e[i].next) { 23 int to=e[i].to;if(to==fa||vis[to]) continue; 24 findroot(to,x); 25 son[x]+=son[to]; 26 f[x]=max(f[x],son[to]); 27 } 28 f[x]=max(f[x],sum-son[x]); 29 if(f[x]<f[root]) root=x; 30 return; 31 } 32 void dfs(int x,int fa,int d,int dep) { 33 dis[++num]=d;b[num]=dep; 34 for(int i=head[x];i>=0;i=e[i].next) { 35 int to=e[i].to;if(to==fa||vis[to]) continue; 36 if(d+e[i].val>k) continue; 37 dfs(to,x,d+e[i].val,dep+1); 38 } 39 } 40 void work(int x) { 41 vis[x]=1; 42 bool flag=0; 43 for(int i=head[x];i>=0;i=e[i].next) { 44 num=0; 45 int to=e[i].to;if(vis[to]) continue; 46 if(e[i].val>k) continue; 47 dfs(to,x,e[i].val,1); 48 for(int j=1;j<=num;j++) if(dis[j]==k) ans=min(ans,b[j]); 49 if(flag) 50 for(int j=1;j<=num;j++) 51 if(dis[j]<=k&&v[k-dis[j]]==x) ans=min(ans,b[j]+tot[k-dis[j]]); 52 for(int j=1;j<=num;j++) 53 if(dis[j]<=k) { 54 if(v[dis[j]]!=x) v[dis[j]]=x,tot[dis[j]]=b[j]; 55 else tot[dis[j]]=min(tot[dis[j]],b[j]); 56 } 57 flag=1; 58 } 59 for(int i=head[x];i>=0;i=e[i].next) { 60 int to=e[i].to; 61 if(vis[to]) continue; 62 root=0;f[0]=n;sum=son[to]; 63 findroot(to,x); 64 work(root); 65 } 66 } 67 int main() { 68 //freopen("gg.in","r",stdin); 69 memset(head,-1,sizeof(head)); 70 scanf("%d%d",&n,&k); 71 for(int i=1;i<n;i++) { 72 int u,v,t; 73 scanf("%d%d%d",&u,&v,&t); 74 add(u+1,v+1,t);add(v+1,u+1,t); 75 } 76 sum=n;ans=n;f[0]=n; 77 findroot(1,0); 78 work(root); 79 if(ans==n) printf("-1"); 80 else printf("%d",ans); 81 }