题目:一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.
点分治,我们考虑经过根节点的路径,t[x]表示路径长为x时最少的边数,然后每次拿栈记下来清空。
注意先搜索再更新,这样可以避免同一子树内互相到达。
By:大奕哥
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=2e5+10,inf=1e9,M=1e6+10;; 4 int n,k,rt,cnt,head[N],s[N],f[N],t[M],ans,maxn,sta[N],top,dis[N],d[N]; 5 bool v[N]; 6 struct node{ 7 int to,nex,w; 8 }e[N<<1]; 9 void add(int x,int y,int w) 10 { 11 e[++cnt].w=w;e[cnt].nex=head[x];e[cnt].to=y;head[x]=cnt; 12 } 13 void getrt(int x,int fa) 14 { 15 s[x]=1;f[x]=0; 16 for(int i=head[x];i;i=e[i].nex) 17 { 18 int y=e[i].to; 19 if(y==fa||v[y])continue; 20 getrt(y,x); 21 f[x]=max(f[x],s[y]); 22 s[x]+=s[y]; 23 } 24 f[x]=max(f[x],maxn-s[x]); 25 if(f[x]<f[rt])rt=x; 26 } 27 void calc(int x,int fa) 28 { 29 if(dis[x]<=k)ans=min(ans,t[k-dis[x]]+d[x]); 30 for(int i=head[x];i;i=e[i].nex) 31 { 32 int y=e[i].to; 33 if(v[y]||y==fa)continue; 34 dis[y]=dis[x]+e[i].w; 35 d[y]=d[x]+1; 36 calc(y,x); 37 } 38 } 39 void update(int x,int fa) 40 { 41 if(dis[x]<=k)t[dis[x]]=min(t[dis[x]],d[x]),sta[++top]=dis[x]; 42 for(int i=head[x];i;i=e[i].nex) 43 { 44 int y=e[i].to; 45 if(v[y]||y==fa)continue; 46 update(y,x); 47 } 48 } 49 void work(int x) 50 { 51 v[x]=1;top=0;t[0]=0; 52 for(int i=head[x];i;i=e[i].nex) 53 { 54 int y=e[i].to; 55 if(v[y])continue; 56 dis[y]=e[i].w;d[y]=1; 57 calc(y,x); 58 update(y,x); 59 } 60 for(int i=1;i<=top;++i)t[sta[i]]=inf; 61 for(int i=head[x];i;i=e[i].nex) 62 { 63 int y=e[i].to; 64 if(v[y])continue; 65 maxn=s[y];rt=0; 66 getrt(y,x); 67 work(rt); 68 } 69 } 70 int main() 71 { 72 scanf("%d%d",&n,&k); 73 int x,y,w; 74 for(int i=1;i<n;++i) 75 { 76 scanf("%d%d%d",&x,&y,&w); 77 x++;y++; 78 add(x,y,w);add(y,x,w); 79 } 80 memset(t,0x3f,sizeof(t)); 81 maxn=f[0]=ans=n; 82 getrt(1,0); 83 work(rt); 84 if(ans==n)puts("-1"); 85 else printf("%d ",ans); 86 return 0; 87 }