洛谷P4178 Tree (点分治)

题目描述

给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K

输入输出格式

输入格式:

 

N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k

 

输出格式:

 

一行,有多少对点之间的距离小于等于k

 

输入输出样例

输入样例#1: 
7
1 6 13 
6 3 9 
3 5 7 
4 1 3 
2 4 20 
4 7 2 
10
输出样例#1: 
5

题解:点分裸题,考虑分治中的暴力,将所有的重心子树中的点到中心的距离排序,对于一组l-r之间如果d[l]+d[r]<=k,显然d[l]+d[i](i<r)时都满足d[l]+d[i]<=k,可以统计答案,类似尺取的思想。
总复杂度是O(nlognlogn)

代码如下:
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mp make_pair
#define pii pair<int,int>
using namespace std;

vector<pii> g[40010];
int n,k,f[40010],vis[40010],size[40010],di[40010],cnt,ans;

void get_size(int now,int fa)
{
    size[now]=1;
    f[now]=fa;
    for(int i=0;i<g[now].size();i++)
    {
        if(vis[g[now][i].first]||g[now][i].first==fa) continue;
        get_size(g[now][i].first,now);
        size[now]+=size[g[now][i].first];
    }
}

int get_zx(int now,int fa)
{
    if(size[now]==1) return now;
    int son,maxson=-1;
    for(int i=0;i<g[now].size();i++)
    {
        if(vis[g[now][i].first]||g[now][i].first==fa) continue;
        if(maxson<size[g[now][i].first])
        {
            maxson=size[g[now][i].first];
            son=g[now][i].first;
        }
    }
    int zx=get_zx(son,now);
    while(size[zx]<(size[now]-size[zx])*2) zx=f[zx];
    return zx;
}

void get(int now,int fa,int dis)
{
    di[++cnt]=dis;
    for(int i=0;i<g[now].size();i++)
    {
        if(vis[g[now][i].first]||g[now][i].first==fa) continue;
        get(g[now][i].first,now,dis+g[now][i].second);
    }
}

int calc(int now,int dis)
{
    cnt=0;
    int tmp=0;
    get(now,0,dis);
    sort(di+1,di+cnt+1);
    int l=1,r=cnt;
    while(l<=r)
    {
        if(di[l]+di[r]<=k)
        {
            tmp+=r-l;
            l++;
        }
        else r--;
    }
    return tmp;
}

void solve(int now)
{
    ans+=calc(now,0);
    vis[now]=1;
    for(int i=0;i<g[now].size();i++)
    {
        if(vis[g[now][i].first]) continue;
        ans-=calc(g[now][i].first,g[now][i].second);
        get_size(g[now][i].first,0);
        int zx=get_zx(g[now][i].first,0);
        solve(zx);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int from,to,cost;
        scanf("%d%d%d",&from,&to,&cost);
        g[from].push_back(mp(to,cost));
        g[to].push_back(mp(from,cost));
    }
    scanf("%d",&k);
    solve(1);
    printf("%d\n",ans);
}

 

 
posted @ 2018-08-06 20:28  Styx-ferryman  阅读(198)  评论(0编辑  收藏  举报