• [POJ 1741] Tree


    Link:

    POJ 1741 传送门

    Solution:

    此题的难点在于点分治上的统计

    如果依然采取每棵子树的结果与之前所有子树的结果合并的方式会比较麻烦

    同时复杂度可能超过$O(n*log(n))$的限制

    其实可以用一个简单的容斥来在$O(n*log(n))$统计结果:

    先将所有点到重心的距离排序,维护左右指针来直接统计结果

    但这样明显会重复计算两个点在同一棵子树中的情况,按照同样的操作将其除去即可

    Code:

    //by NewErA
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    typedef pair<int,int> P;
    
    const int MAXN=10005;
    vector<P> G[MAXN];vector<int> tmp;
    int n,k,mx_sub[MAXN],sz[MAXN],vis[MAXN],v_sum=0,root,res=0;
    int dist[MAXN];
    
    void getroot(int x,int anc)
    {
        sz[x]=1;mx_sub[x]=0;
        for(int i=0;i<G[x].size();i++)
        {
            int v=G[x][i].first;
            if(v==anc || vis[v]) continue;
            getroot(v,x);sz[x]+=sz[v];
            mx_sub[x]=max(mx_sub[x],sz[v]);
        }
        mx_sub[x]=max(mx_sub[x],v_sum-sz[x]);
        if(mx_sub[x]<mx_sub[root]) root=x;
    }
    
    void cal_dep(int x,int anc)
    {
        tmp.push_back(dist[x]);
        for(int i=0;i<G[x].size();i++)
        {
            int v=G[x][i].first;
            if(v==anc || vis[v]) continue;
            dist[v]=dist[x]+G[x][i].second;
            cal_dep(v,x);
        }
    }
    
    int cal(int x,int start_point)
    {
        tmp.clear();dist[x]=start_point;
        cal_dep(x,0);sort(tmp.begin(),tmp.end());
        int ret=0,l=0,r=tmp.size()-1;
        while(l<r)
        {
            if(tmp[l]+tmp[r]<=k)
                ret+=(r-l),l++;
            else r--;
        }
        return ret;
    }
    
    void solve(int x)
    {
        res+=cal(x,0);vis[x]=true;
        for(int i=0;i<G[x].size();i++)
        {
            int v=G[x][i].first;
            if(vis[v]) continue;
            res-=cal(v,G[x][i].second);
            v_sum=sz[v];getroot(v,root=0);
            solve(root);
        }
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&k)!=EOF && n && k)
        {
            for(int i=0;i<=n;i++) G[i].clear(),vis[i]=mx_sub[i]=0;
            for(int i=1;i<n;i++)
            {
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                G[x].push_back(P(y,z));G[y].push_back(P(x,z));
            }
            mx_sub[0]=v_sum=n;getroot(1,root=0);
            res=0;solve(root);
            printf("%d
    ",res);
        }
        return 0;
    }

    Review:

    点分治中可用容斥的思想来统计

    先计算任意两点的结果,再减去两点在同一棵子树中的结果(重心转移后会重复计算)

  • 相关阅读:
    41.js延迟加载的方式有哪些?
    39、[“1”, “2”, “3”].map(parseInt) 答案是多少
    38.null,undefined 的区别?
    35.说几条写JavaScript的基本规范?
    34.介绍js有哪些内置对象?
    问题解决Android studio遇到 java.lang.OutOfMemoryError: GC app:transformClassesWithDexForDebug解决方法 以及gradle优化
    Multiple dex files define
    Retrofit2.0+RxJava2.0问题
    【转】Android Shape绘制虚线在手机端查看是实线的问题
    极光使用整理
  • 原文地址:https://www.cnblogs.com/newera/p/9303056.html
Copyright © 2020-2023  润新知