zoukankan      html  css  js  c++  java
  • 树分治专题(学习笔记+做题记录)

    点分治

      点分治可以用来处理有关树上路径的问题

      首先选取当前子树的重心作为分治点,因为重心可保证最大的子树不超过(u/2),这样每次递归的处理下去,复杂度是(nlogn)的

      求重心代码:

    void getroot(int u,int par){
        sz[u]=1,son[u]=0;
        for(int i=h[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(vis[v] || v==par) continue;
            getroot(v,u);
            sz[u]+=sz[v];
            son[u]=max(son[u],sz[v]); 
        }
        son[u]=max(son[u],sum-sz[u]);
        if(son[u]<maxson){
            maxson=son[u];
            rt=u;
        }
    }
    View Code

      

    题目:

    IOI2011 Race

      题意:给定一棵树,每条边有边权,求一条路径,权值和等于k,且边的数量最小

      solution:

      记录s[i],当前点到分治中心的边数,d[i]当前点到分治中心的距离,f[i]已统计完的子树中,距分治中心距离为 i 的路径中的最小边数

      处理当前子树时,直接用f数组更新答案

      每次统计完一棵子树的答案之后,更新f数组

      这样既可以考虑到所有的路径,又避免重复统计答案

      

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 1000010;
    const int INF = 1e9+7;
    
    int n,k,ans=INF;
    int sum,maxs;
    
    int h[maxn],size;
    struct E{
        int to,next,cost;
    }e[maxn<<1];
    void add(int u,int v,int w){
        e[++size].to=v;
        e[size].next=h[u];
        e[size].cost=w;
        h[u]=size;
    }
    
    int rt;
    int vis[maxn],sz[maxn],son[maxn];
    int d[maxn],s[maxn],f[maxn*10],c[maxn],ton[maxn*10],tot,cnt;
    
    void getroot(int u,int par){
        sz[u]=1,son[u]=0;
        for(int i=h[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(v==par||vis[v]) continue;
            getroot(v,u);
            sz[u]+=sz[v];
            son[u]=max(son[u],sz[v]);
        }
        son[u]=max(son[u],sum-sz[u]);
        if(son[u]<maxs){
            maxs=son[u];
            rt=u;
        }
    }
    
    void dfs(int u,int par,int chang){
        d[u]=d[par]+chang;
        if(d[u]<=k) ton[++tot]=d[u];
        s[u]=s[par]+1;
        c[++cnt]=u;
        if(k>=d[u]) ans=min(ans,f[k-d[u]]+s[u]);
        for(int i=h[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(vis[v]||v==par) continue;
            dfs(v,u,e[i].cost);
        }
    }
    
    void solve(int u){
        vis[u]=1;
        tot=0; f[0]=0; d[u]=0; s[u]=0;
        for(int i=h[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(vis[v]) continue;
            cnt=0; 
            dfs(v,u,e[i].cost);
            
            for(int j=1;j<=cnt;++j){
                if(d[c[j]]>k) continue;
                f[d[c[j]]]=min(f[d[c[j]]],s[c[j]]);
            }
        }
        
        for(int i=1;i<=tot;++i) f[ton[i]]=INF;
        
        for(int i=h[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(vis[v]) continue;
            sum=sz[v],maxs=INF,rt=0;
            getroot(v,0);
            solve(rt);
        }
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f;}
    
    int main(){
        memset(h,-1,sizeof(h));
        n=read(),k=read();
        int u,v; ll w;
        for(int i=1;i<=1000000;++i) f[i]=INF;
        for(int i=1;i<n;++i){
            u=read(),v=read(),w=read();
            u++,v++;
            add(u,v,w),add(v,u,w);
        }
        
        sum=n; maxs=INF;
        getroot(1,0);
        
        solve(rt);
        
        printf("%d\n",ans==INF?-1:ans);
        
        return 0;
    }
    View Code

    Spoj 1825 Free tour II
      

  • 相关阅读:
    对Spring <context:annotation-config/>的理解
    Javascript this指针
    go 打造世界最快的go模板引擎gorazor 2.0
    swagger 部署(Mac )
    Ab测试
    Nginx tcp限制并发、IP、记日志
    Nginx proxy_protocol协议与realip模块
    数据结构之回溯
    数据结构之分治
    数据结构之二分查找
  • 原文地址:https://www.cnblogs.com/tuchen/p/10482916.html
Copyright © 2011-2022 走看看