[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
",ans!=inf?ans:-1);
115     return 0;
116 }
原文地址:https://www.cnblogs.com/skylee03/p/8194305.html