POJ 1741 树分治入门

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAX=1e4+5;
//点分治 CurSize-树当前大小 CurRoot-当前树的根
//Son[i]节点i的子节点的个数 D[i]节点i到CurRoot的距离 F[i]节点i最大子树的大小
int N,K,CurSize,CurRoot,Ans,Son[MAX],D[MAX],F[MAX];
bool Used[MAX]; //Used[i]节点i是否计算完成
vector<pair<int,int> > G[MAX]; //Graph
vector<int> Depth;  //把计算后的D[i]保存进来
void GetRoot(int s,int pre)
{
    Son[s]=0,F[s]=0;
    for (int i=0; i<(int)G[s].size(); i++)
    {
        if (G[s][i].first==pre||Used[G[s][i].first])
            continue;
        GetRoot(G[s][i].first,s);
        Son[s]+=Son[G[s][i].first]+1;
        F[s]=max(F[s],Son[G[s][i].first]+1);
    }
    F[s]=max(F[s],CurSize-Son[s]-1);
    if (F[s]<F[CurRoot])
        CurRoot=s;
}
void GetDepth(int s,int pre)
{
    Depth.push_back(D[s]);
    Son[s]=0;
    for (int i=0; i<(int)G[s].size(); i++)
    {
        if (G[s][i].first==pre||Used[G[s][i].first])
            continue;
        D[G[s][i].first]=D[s]+G[s][i].second;
        GetDepth(G[s][i].first,s);
        Son[s]+=Son[G[s][i].first]+1;
    }
}
int Calc(int s,int init)
{
    Depth.clear();
    D[s]=init;
    GetDepth(s,0);
    sort(Depth.begin(),Depth.end());
    int res=0;
    for (int l=0,r=Depth.size()-1; l<r;)
        if (Depth[l]+Depth[r]<=K)
            res+=r-l++;
        else
            r--;
    return res;
}
void Solve(int s)
{
    Ans+=Calc(s,0); //求出所有D[i]+D[j]<=K的路径的个数
    Used[s]=true;
    for (int i=0; i<(int)G[s].size(); i++)
    {
        if (!Used[G[s][i].first])
        {
            Ans-=Calc(G[s][i].first,G[s][i].second); //再减去i和j在同一子树的情况
            F[0]=CurSize=Son[G[s][i].first]+1;
            GetRoot(G[s][i].first,CurRoot=0);
            Solve(CurRoot);
        }
    }
}
int main()
{
    cin.sync_with_stdio(false);
    while(cin>>N>>K)
    {
        if (N==0&&K==0)
            break;
        int a,b,c;
        memset(Used,false,sizeof(Used));
        for (int i=1; i<=N; i++)
            G[i].clear();
        for (int i=1; i<N; i++)
        {
            cin>>a>>b>>c;
            G[a].push_back(make_pair(b,c));
            G[b].push_back(make_pair(a,c));
        }
        F[0]=CurSize=N;
        GetRoot(1,CurRoot=0);
        Ans=0;
        Solve(CurRoot);
        cout<<Ans<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值