[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:

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

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

原文地址:https://www.cnblogs.com/newera/p/9303056.html