BZOJ2599:[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
Solution
开一个100W的数组t,t[i]表示到当前处理的树的根距离为i的最小边数
对于点x,我们要统计经过x的路径的话
就分别统计x的每颗子树,在统计一颗子树的时候用t[i]更新答案
并在每统计完一颗子树后更新t数组
↑这样是为了防止统计答案的时候两个点在同一子树里
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (200000+100) 5 using namespace std; 6 struct node 7 { 8 int to,next,len; 9 }edge[N*2]; 10 int n,k,sum,root,ans,INF; 11 int head[N],num_edge; 12 int depth[N],d[N],size[N],maxn[N]; 13 int dis[N],t[N*5]; 14 bool vis[N]; 15 16 void add(int u,int v,int l) 17 { 18 edge[++num_edge].to=v; 19 edge[num_edge].len=l; 20 edge[num_edge].next=head[u]; 21 head[u]=num_edge; 22 } 23 24 void Get_root(int x,int fa) 25 { 26 size[x]=1; maxn[x]=0; 27 for (int i=head[x];i!=0;i=edge[i].next) 28 if (edge[i].to!=fa && !vis[edge[i].to]) 29 { 30 Get_root(edge[i].to,x); 31 size[x]+=size[edge[i].to]; 32 maxn[x]=max(maxn[x],size[edge[i].to]); 33 } 34 maxn[x]=max(maxn[x],sum-size[x]); 35 if (maxn[x]<maxn[root]) root=x; 36 } 37 38 void Calc(int x,int fa) 39 { 40 if (dis[x]<=k) ans=min(ans,depth[x]+t[k-dis[x]]); 41 for (int i=head[x];i!=0;i=edge[i].next) 42 if (!vis[edge[i].to] && edge[i].to!=fa) 43 { 44 dis[edge[i].to]=dis[x]+edge[i].len; 45 depth[edge[i].to]=depth[x]+1; 46 Calc(edge[i].to,x); 47 } 48 } 49 50 void Reset(int x,int fa,int flag) 51 { 52 if (dis[x]<=k) 53 { 54 if (flag) t[dis[x]]=min(t[dis[x]],depth[x]); 55 else t[dis[x]]=INF; 56 } 57 for (int i=head[x];i!=0;i=edge[i].next) 58 if (edge[i].to!=fa && !vis[edge[i].to]) 59 Reset(edge[i].to,x,flag); 60 } 61 62 void Solve(int x) 63 { 64 vis[x]=true; t[0]=0; 65 for (int i=head[x];i!=0;i=edge[i].next) 66 if (!vis[edge[i].to]) 67 { 68 depth[edge[i].to]=1; 69 dis[edge[i].to]=edge[i].len; 70 Calc(edge[i].to,0); 71 Reset(edge[i].to,0,1); 72 } 73 for (int i=head[x];i!=0;i=edge[i].next) 74 if (!vis[edge[i].to]) 75 Reset(edge[i].to,0,0); 76 for (int i=head[x];i!=0;i=edge[i].next) 77 if (!vis[edge[i].to]) 78 { 79 sum=size[edge[i].to]; 80 root=0; 81 Get_root(edge[i].to,0); 82 Solve(root); 83 } 84 85 } 86 87 int main() 88 { 89 int u,v,l; 90 memset(t,0x3f,sizeof(t)); 91 memset(&INF,0x3f,sizeof(INF)); 92 scanf("%d%d",&n,&k); 93 for (int i=1;i<=n-1;++i) 94 { 95 scanf("%d%d%d",&u,&v,&l); 96 u++; v++; 97 add(u,v,l); add(v,u,l); 98 } 99 ans=sum=maxn[0]=n; 100 Get_root(1,0); 101 Solve(root); 102 printf("%d",ans==n?-1:ans); 103 }