[IOI2011]Race
题目大意:
给你一棵n个结点的带边权的树,问长度恰好为k的路径至少经过多少条边?
思路:
重心剖分。
对于每次剖分出来的子树,存一下从根出发的长度为i的路径至少经过几条边f[i]。
注意要保证经过根结点,所以一次整棵树DFS结束后才能更新f。
重置数组f的时候,不能从i到k重置,而应该重新遍历整棵树,把会用到的那些值重置。
最后就是各种低级错误,比如一开始把size[x]+=size[y]中x和y打反,导致除了叶子结点的子树,其它子树大小都是0,剖不到重心上。
最后还是拼命TLE,最后发现原来是freopen没删掉。
1 #pragma GCC optimize(3) 2 #pragma GCC optimize("unroll-loops") 3 #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") 4 #include<cstdio> 5 inline int getint() { 6 register char ch; 7 while(!__builtin_isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(__builtin_isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int inf=0x7fffffff; 13 const int N=200001,K=1000001; 14 int h[N],to[N<<1],w[N<<1],next[N<<1],cnt; 15 inline void add_edge(const int &u,const int &v,const int &l) { 16 to[++cnt]=v; w[cnt]=l; next[cnt]=h[u]; h[u]=cnt; 17 to[++cnt]=u; w[cnt]=l; next[cnt]=h[v]; h[v]=cnt; 18 } 19 int size[N],f[K],s,mn,cur,k,ans; 20 bool mark[N]; 21 inline int max(const int &a,const int &b) { 22 return a>b?a:b; 23 } 24 inline int min(const int &a,const int &b) { 25 return a<b?a:b; 26 } 27 void dfs(const int &x,const int &par) { 28 size[x]=1; 29 int mx=0; 30 for(int i=h[x];i;i=next[i]) { 31 const int &y=to[i]; 32 if(y==par||mark[y]) continue; 33 dfs(y,x); 34 size[x]+=size[y]; 35 mx=max(mx,size[y]); 36 } 37 mx=max(mx,s-size[x]); 38 if(mx<mn) { 39 mn=mx; 40 cur=x; 41 } 42 } 43 inline int get_center(const int &x) { 44 mn=inf; 45 dfs(x,0); 46 return cur; 47 } 48 int get_size(const int &x,const int &par) { 49 int size=1; 50 for(int i=h[x];i;i=next[i]) { 51 const int &y=to[i]; 52 if(y==par||mark[y]) continue; 53 size+=get_size(y,x); 54 } 55 return size; 56 } 57 void dp(const int &x,const int &par,const int &dis,const int &dep) { 58 if(dis>k) return; 59 if(dis==k||f[k-dis]!=inf) { 60 ans=min(ans,dep+f[k-dis]); 61 } 62 for(int i=h[x];i;i=next[i]) { 63 const int &y=to[i]; 64 if(y==par||mark[y]) continue; 65 dp(y,x,dis+w[i],dep+1); 66 } 67 } 68 void set(const int &x,const int &par,const int &dis,const int &dep) { 69 if(dis>k) return; 70 f[dis]=min(f[dis],dep); 71 for(int i=h[x];i;i=next[i]) { 72 const int &y=to[i]; 73 if(y==par||mark[y]) continue; 74 set(y,x,dis+w[i],dep+1); 75 } 76 } 77 void reset(const int &x,const int &par,const int &dis) { 78 if(dis>k) return; 79 f[k-dis]=inf; 80 for(int i=h[x];i;i=next[i]) { 81 const int &y=to[i]; 82 if(y==par||mark[y]) continue; 83 reset(y,x,dis+w[i]); 84 } 85 } 86 void solve(const int &x) { 87 s=get_size(x,0); 88 const int u=get_center(x); 89 mark[u]=true; 90 for(int i=h[u];i;i=next[i]) { 91 const int &v=to[i]; 92 if(mark[v]) continue; 93 solve(v); 94 } 95 reset(u,0,0); 96 f[0]=0; 97 for(register int i=h[u];i;i=next[i]) { 98 const int &v=to[i]; 99 if(mark[v]) continue; 100 dp(v,u,w[i],1); 101 set(v,u,w[i],1); 102 } 103 mark[u]=false; 104 } 105 int main() { 106 const int n=getint(); 107 k=getint(); 108 for(register int i=1;i<n;i++) { 109 const int u=getint()+1,v=getint()+1,w=getint(); 110 add_edge(u,v,w); 111 } 112 ans=inf; 113 solve(1); 114 __builtin_printf("%d\n",ans!=inf?ans:-1); 115 return 0; 116 }