zoukankan      html  css  js  c++  java
  • 点分治模板

    luogu_3806

    近些日子学了点分治,当然只是学了个模板。

    所谓点分治,使用于处理树上路径的一种分治手段。因为利用了重心的性质,时间复杂度可以保证呢。

    所谓算法流程

    1. 选取当前子树的重心

    2. 计算路径总数,不管路径是否过当前重心(后面会去重)

    3. 计算起点和终点在同一颗子树中的合法路径(因为这条路径不是简单路径),并在答案中减去

    4. 将子树剔除出来,并在子树中重复此过程

    需要注意的点

    在处理路径(也就是深度时),一定要重新计算子节点个数(因为根有可能转变)
    
    时间复杂很玄学
    
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    
    using std::sort;
    using std::max;
    
    const int maxn=10100;
    const int inf=0x7fffffff;
    
    struct node
    {
        int p;
        int nxt;
        int v;
    };
    
    node line[maxn<<1];
    int head[maxn],tail;
    int dep[maxn],f[maxn],size[maxn],vis[maxn],root,sum;
    int d[maxn],tot;
    int ans[10000011];
    
    void add(int a,int b,int c)
    {
        line[++tail].p=b;
        line[tail].v=c;
        line[tail].nxt=head[a];
        head[a]=tail;
        return ;
    }
    
    void get_hry(int now,int fa)
    {
        int v;
        f[now]=0;size[now]=1;
        for(int i=head[now];i;i=line[i].nxt)
        {
            v=line[i].p;
            if(vis[v]||v==fa)   continue;
            get_hry(v,now);
            size[now]+=size[v];
            f[now]=max(f[now],size[v]);
        }
        f[now]=max(f[now],sum-size[now]);//最后和他上面的节点数取个最大值
        if(f[root]>f[now])  root=now;
    }
    
    void get_dep(int now,int fa)//处理路径,这时一定要重新计算size
    {
        int v;d[++tot]=dep[now];
        size[now]=1;
        for(int i=head[now];i;i=line[i].nxt)
        {
            v=line[i].p;
            if(v==fa||vis[v])   continue;
            dep[v]=dep[now]+line[i].v;
            get_dep(v,now);
            size[now]+=size[v];
        }
        return ;
    }
    
    void calc(int now,int Dep,int delta)//核心的计算函数
    {
        dep[now]=Dep;tot=0;
        get_dep(now,0);
        sort(d+1,d+1+tot);
        for(int i=1;i<=tot;i++)
            for(int j=1;j<=tot;j++) if(i!=j)
                ans[d[i]+d[j]]+=delta;//桶
        return ;
    }
    
    void solve(int now)
    {
        vis[now]=1;//断开连接
        calc(now,0,1);
        for(int i=head[now];i;i=line[i].nxt)
        {
            int v=line[i].p;
            if(vis[v])  continue;
            calc(v,line[i].v,-1);
            root=0;sum=size[v];//计算子树的重心
            get_hry(v,0);
            solve(root);
        }
        return ;
    }
    
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1,a,b,c;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);add(b,a,c);
        }
        root=0;sum=n;//root,和sum分别是当前联通块内的根和节点数
        f[root]=inf;//操作一波
        get_hry(1,0);
        solve(root);//点分治
        for(int i=1,k;i<=m;i++)
        {
            scanf("%d",&k);
            if(ans[k])  printf("AYE
    ");
            else    printf("NAY
    ");
        }
        return 0;
    }
    
    
  • 相关阅读:
    VS2010下配置CxImage
    Visual Studio 2010 开发配置
    主机屋使用感受
    Web开发者必备的20款超赞jQuery插件
    自动页面居中
    jQuery+CSS打造的网页背景颜色切换效果
    小按钮,大学问
    【网站开发必备】——12款响应式 Lightbox(灯箱)效果插件
    修正 IE 的双倍页边距 bug
    a>b?a:b
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/10245850.html
Copyright © 2011-2022 走看看