BZOJ 2599: [IOI2011]Race (點分治)

題目描述

給一棵樹,每條邊有權。求一條簡單路徑,權值和等於$K$ ,且邊的數量最小。ios

輸入輸出格式

輸入格式:git

第一行:兩個整數$n,k$數組

第二至$n$行:每行三個整數,表示一條無向邊的兩端和權值 (注意點的編號從$n$開始)。spa

輸出格式:code

一個整數,表示最小邊數量。blog

若是不存在這樣的路徑,輸出 -11 。get

輸入輸出樣例

輸入樣例#1:  複製
4 3
0 1 1
1 2 2
1 3 4
輸出樣例#1:  複製
2

說明

$n\le 200000,K\le 1000000$
it

題解io

  咱們用一個數組$f[j]$表示點分到當前子樹中時路徑長度爲$j$的最小邊數class

  而後每一棵子樹裏去$dfs$一遍更新$f$數組,而後用$f$數組相加更新答案

  複雜度爲$O(nlogn)$

 1 //minamoto
 2 #include<cstdio>
 3 #include<iostream>
 4 #define ll long long
 5 using namespace std;  6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 7 char buf[1<<21],*p1=buf,*p2=buf;  8 template<class T>inline int cmax(T&a,const T&b){return a<b?a=b,1:0;}  9 template<class T>inline int cmin(T&a,const T&b){return a>b?a=b,1:0;} 10 inline int read(){ 11     #define num ch-'0'
12     char ch;bool flag=0;int res; 13     while(!isdigit(ch=getc())) 14     (ch=='-')&&(flag=true); 15     for(res=num;isdigit(ch=getc());res=res*10+num); 16     (flag)&&(res=-res); 17     #undef num
18     return res; 19 } 20 char sr[1<<21],z[20];int C=-1,Z; 21 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 22 inline void print(int x){ 23     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 24     while(z[++Z]=x%10+48,x/=10); 25     while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 26 } 27 const int N=200005,K=1000005; 28 int ver[N<<1],head[N],Next[N<<1],edge[N<<1]; 29 int n,k,ans,tot,size,sz[N],son[N],rt,cnt[K];bool vis[N];ll d[N]; 30 inline void add(int u,int v,int e){ 31     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e; 32     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=e; 33 } 34 void findrt(int u,int fa){ 35     sz[u]=1,son[u]=0; 36     for(int i=head[u];i;i=Next[i]){ 37         int v=ver[i];if(v==fa||vis[v]) continue; 38         findrt(v,u),sz[u]+=sz[v],cmax(son[u],sz[v]); 39  } 40     cmax(son[u],size-sz[u]); 41     if(son[u]<son[rt]) rt=u; 42 } 43 void dfs(int u,int fa,int dep){ 44     if(d[u]>=0&&d[u]<=k) cmin(ans,dep+cnt[k-d[u]]); 45     for(int i=head[u];i;i=Next[i]){ 46         int v=ver[i]; 47         if(v!=fa&&!vis[v]){ 48             d[v]=d[u]+edge[i],dfs(v,u,dep+1); 49  } 50  } 51 } 52 void update(int u,int fa,int dep,int opt){ 53     if(d[u]>=0&&d[u]<=k) 54     opt?cmin(cnt[d[u]],dep):cnt[d[u]]=n; 55     for(int i=head[u];i;i=Next[i]){ 56         int v=ver[i]; 57         if(!vis[v]&&v!=fa) 58         update(v,u,dep+1,opt); 59  } 60 } 61 void solve(int u){ 62     vis[u]=true,cnt[0]=0; 63     for(int i=head[u];i;i=Next[i]){ 64         int v=ver[i]; 65         if(!vis[v]) 66         d[v]=edge[i],dfs(v,0,1),update(v,0,1,1); 67  } 68     for(int i=head[u];i;i=Next[i]){ 69         int v=ver[i]; 70         if(!vis[v]) 71         update(v,0,1,0); 72  } 73     int totsz=size; 74     for(int i=head[u];i;i=Next[i]){ 75         int v=ver[i]; 76         if(!vis[v]){ 77             rt=0,size=sz[v]; 78             findrt(v,0),solve(rt); 79  } 80  } 81 } 82 int main(){ 83     n=read(),k=read(),ans=n; 84     for(int i=1;i<n;++i){ 85         int u=read()+1,v=read()+1,e=read();add(u,v,e); 86  } 87     for(int i=1;i<=k;++i) cnt[i]=n; 88     son[rt=0]=n+1,size=n,findrt(1,0),solve(rt); 89     print(ans==n?-1:ans); 90  Ot(); 91     return 0; 92 }
相關文章
相關標籤/搜索