• POJ1741 Tree(树分治)


     题意:

    求树上距离小于等于K的点对有多少个

    思路:

    每次分治,我们首先算出重心,为了计算重心,需要进行两次dfs,第一次把以每个结点为根的子树大小求出来,第二次是从这些结点中找重心

    找到重心后,需要统计所有结点到重心的距离,看其中有多少对小于等于K

    但是这些求出来满足小于等于K的里面只有那些路径经过重心的点对才是有效的,也就是说在同一颗子树上的肯定不算数的,所以对每颗子树,把子树内部的满足条件的点对减去。

    /* ***********************************************
    Author        :devil
    ************************************************ */
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <set>
    #include <stack>
    #include <map>
    #include <string>
    #include <cmath>
    #include <stdlib.h>
    #define LL long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define dep(i,a,b) for(int i=a;i>=b;i--)
    #define ou(a) printf("%d
    ",a)
    #define pb push_back
    #define mkp make_pair
    template<class T>inline void rd(T &x)
    {
        char c=getchar();
        x=0;
        while(!isdigit(c))c=getchar();
        while(isdigit(c))
        {
            x=x*10+c-'0';
            c=getchar();
        }
    }
    #define IN freopen("in.txt","r",stdin);
    #define OUT freopen("out.txt","w",stdout);
    using namespace std;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    const int N=1e4+10;
    int n,k,x,y,w,root,ans,cnt,m;
    int sum[N],ma[N],deep[N],d[N];
    bool vis[N];
    vector<pair<int,int> >eg[N];
    void dfs(int u,int fa)
    {
        sum[u]=1,ma[u]=0;
        for(int i=0;i<eg[u].size();i++)
        {
            int v=eg[u][i].first;
            if(v==fa||vis[v]) continue;
            dfs(v,u);
            sum[u]+=sum[v];
            ma[u]=max(ma[u],sum[v]);
        }
        ma[u]=max(ma[u],m-sum[u]);
        if(ma[u]<ma[root]) root=u;
    }
    void getdeep(int u,int fa)
    {
        deep[++deep[0]]=d[u];
        for(int i=0;i<eg[u].size();i++)
        {
            int v=eg[u][i].first;
            if(v==fa||vis[v]) continue;
            d[v]=d[u]+eg[u][i].second;
            getdeep(v,u);
        }
    }
    int cal(int u,int now)
    {
        d[u]=now;deep[0]=0;
        getdeep(u,0);
        sort(deep+1,deep+1+deep[0]);
        int ret=0,l=1,r=deep[0];
        while(l<r)
        {
            if(deep[l]+deep[r]<=k)
            {
                ret=ret+r-l;
                l++;
            }
            else r--;
        }
        return ret;
    }
    void work(int u)
    {
        ans+=cal(u,0);
        vis[u]=1;
        for(int i=0;i<eg[u].size();i++)
        {
            int v=eg[u][i].first;
            if(vis[v]) continue;
            ans-=cal(v,eg[u][i].second);
            m=sum[v];
            root=0;
            dfs(v,0);
            work(root);
        }
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        //IN
    #endif
        ma[0]=inf;
        while(~scanf("%d%d",&n,&k)&&n)
        {
            for(int i=1; i<=n; i++) eg[i].clear();
            root=0;ans=0;cnt=0;m=n;
            memset(vis,0,sizeof(vis));
            for(int i=1; i<n; i++)
            {
                scanf("%d%d%d",&x,&y,&w);
                eg[x].pb(mkp(y,w));
                eg[y].pb(mkp(x,w));
            }
            dfs(1,0);
            work(root);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    #网络流,最小割#洛谷 1344 [USACO4.4]追查坏牛奶Pollutant Control
    #线段树,倒序#CF356A Knight Tournament
    #错排,高精度#洛谷 3182 [HAOI2016]放棋子
    #KMP,dp#洛谷 3426 [POI2005]SZA-Template
    #差分约束系统,Spfa,SLF优化#Hdu 3666 THE MATRIX PROBLEM
    #min_max容斥#Hdu 4336 Card Collector
    #组合计数,卢卡斯定理#D 三元组
    #计数,记忆化搜索#C 连边方案
    #区间dp,离散#D 弱者对决
    #dp#C 公共子序列
  • 原文地址:https://www.cnblogs.com/d-e-v-i-l/p/5987327.html
Copyright © 2020-2023  润新知