山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 2599 [IOI2011]Race (点分治)

 

【题意】

 

    问树中长为k的路径中包含边数最少的路径所包含的边数。

 

【思路】

 

    统计经过根的路径。假设当前枚举到根的第S个子树,若x属于S子树,则有:

        ans<-dep[x]+min{ dep[y] },y属于前S-1个子树,dis[x]<=K

    所以只需要用一个数组t[len]记录前S-1棵子树中长度为len的最少边数即可。t只用开到K的最大值。

    然后分治处理子树。

 

【代码】

 

  1 #include<set>
  2 #include<cmath>
  3 #include<queue>
  4 #include<vector>
  5 #include<cstdio>
  6 #include<cstring>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 11 using namespace std;
 12 
 13 typedef long long ll;
 14 const int N = 1e6+10;
 15 const int inf = 1e9;
 16 
 17 ll read() {
 18     char c=getchar();
 19     ll f=1,x=0;
 20     while(!isdigit(c)) {
 21         if(c=='-') f=-1; c=getchar();
 22     }
 23     while(isdigit(c))
 24         x=x*10+c-'0',c=getchar();
 25     return x*f;
 26 }
 27 
 28 struct Edge {
 29     int v,w,nxt;
 30 }e[N<<1];
 31 int en=1,front[N];
 32 void adde(int u,int v,int w)
 33 {
 34     e[++en]=(Edge){v,w,front[u]}; front[u]=en;
 35 }
 36 
 37 int l1,l2;
 38 int t[N],dep[N],dis[N],ans=inf,list[N];
 39 int vis[N],siz[N],rt,f[N],size,n,K;
 40 
 41 void getroot(int u,int fa) 
 42 {
 43     siz[u]=1; f[u]=0;
 44     trav(u,i) if(e[i].v!=fa&&!vis[e[i].v]){
 45         int v=e[i].v;
 46         getroot(v,u);
 47         siz[u]+=siz[v];
 48         f[u]=max(f[u],siz[v]);
 49     }
 50     f[u]=max(f[u],size-siz[u]);
 51     if(f[u]<f[rt]) rt=u;
 52 }
 53 void dfs(int u,int fa) 
 54 {
 55     list[++l1]=u;
 56     trav(u,i) if(e[i].v!=fa&&!vis[e[i].v]) {
 57         int v=e[i].v;
 58         dis[v]=dis[u]+e[i].w;
 59         dep[v]=dep[u]+1;
 60         dfs(v,u);
 61     }
 62 }
 63 void solve(int u) 
 64 {
 65     vis[u]=1; t[0]=0; 
 66     l1=l2=0;
 67     trav(u,i) if(!vis[e[i].v]) {
 68         int v=e[i].v;
 69         dep[v]=1; dis[v]=e[i].w;
 70         dfs(v,-1);
 71         FOR(j,l2+1,l1) {
 72             if(dis[list[j]]<=K)
 73                 ans=min(ans,dep[list[j]]+t[K-dis[list[j]]]);
 74         }
 75         FOR(j,l2+1,l1)
 76             if(dis[list[j]]<=K) t[dis[list[j]]]=min(t[dis[list[j]]],dep[list[j]]);
 77         l2=l1;
 78     }
 79     FOR(i,0,l1) t[dis[list[i]]]=inf;
 80     trav(u,i) if(!vis[e[i].v]) {
 81         int v=e[i].v; rt=0;
 82         getroot(v,-1); size=siz[v];
 83         solve(rt);
 84     }
 85 }
 86 
 87 int main()
 88 {
 89     freopen("in.in","r",stdin);
 90     freopen("out.out","w",stdout);
 91     n=read(),K=read();
 92     int u,v,w;
 93     FOR(i,1,n-1) {
 94         u=read()+1,v=read()+1,w=read();
 95         adde(u,v,w),adde(v,u,w);
 96     }
 97     FOR(i,1,K) t[i]=n;
 98     size=f[0]=ans=n;
 99     getroot(1,-1);
100     solve(rt);
101     if(ans==n) puts("-1");
102     else printf("%d\n",ans);
103     return 0;
104 }

 

posted on 2016-03-27 10:32  hahalidaxin  阅读(286)  评论(0编辑  收藏  举报