zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    103     return 0;
    104 }
  • 相关阅读:
    排序算法:冒泡排序
    排序算法: 插入排序
    排序算法:折半插入排序
    排序算法:快速排序
    浅谈C/C++回调函数(Callback)& 函数指针
    仿函数
    回溯法:求和
    动态规划:数字和为sum的方法数
    字典序
    剑指offer15 二进制中1的个数
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5325093.html
Copyright © 2011-2022 走看看