POJ 1741 Tree 树的分治

原题链接:http://poj.org/problem?id=1741

题意:

给你棵树,询问有多少点对,使得这条路径上的权值和小于K

题解:

就。。大约就是树的分治

代码:

#include<iostream>
#include<climits>
#include<cstring>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdio>
#define MAX_N 10004
using namespace std;

struct edge{
public:
    int to,length;
    edge(int t,int l):to(t),length(l){}
    edge(){}
};

int N,K;

vector<edge> G[MAX_N];

bool centroid[MAX_N];
int subtree_size[MAX_N];

int ans;

int compute_subtree_size(int v,int p){
    int c=1;
    for(int i=0;i<G[v].size();i++){
        int w=G[v][i].to;
        if(w==p||centroid[w])continue;
        c+=compute_subtree_size(G[v][i].to,v);
    }
    subtree_size[v]=c;
    return c;
}

pair<int,int> search_centroid(int v,int p,int t){
    pair<int,int> res=make_pair(INT_MAX,-1);
    int s=1,m=0;
    for(int i=0;i<G[v].size();i++){
        int w=G[v][i].to;
        if(w==p||centroid[w])continue;

        res=min(res,search_centroid(w,v,t));

        m=max(m,subtree_size[w]);
        s+=subtree_size[w];
    }
    m=max(m,t-s);
    res=min(res,make_pair(m,v));
    return res;
}

void enumeratr_paths(int v,int p,int d,vector<int> &ds){
    ds.push_back(d);
    for(int i=0;i<G[v].size();i++){
        int w=G[v][i].to;
        if(w==p||centroid[w])continue;
        enumeratr_paths(w,v,d+G[v][i].length,ds);
    }
}

int count_pairs(vector<int> &ds){
    int res=0;
    sort(ds.begin(),ds.end());
    int j=ds.size();
    for(int i=0;i<ds.size();i++){
        while(j>0&&ds[i]+ds[j-1]>K)--j;
        res+=j-(j>i?1:0);
    }
    return res/2;
}

void solve_subproblem(int v){
    compute_subtree_size(v,-1);
    int s=search_centroid(v,-1,subtree_size[v]).second;
    centroid[s]=1;

    for(int i=0;i<G[s].size();i++){
        if(centroid[G[s][i].to])continue;
        solve_subproblem(G[s][i].to);
    }

    vector<int> ds;
    ds.push_back(0);
    for(int i=0;i<G[s].size();i++){
        if(centroid[G[s][i].to])continue;

        vector<int> tds;
        enumeratr_paths(G[s][i].to,s,G[s][i].length,tds);

        ans-=count_pairs(tds);
        ds.insert(ds.end(),tds.begin(),tds.end());
    }
    ans+=count_pairs(ds);
    centroid[s]=false;
}

void solve(){
    ans=0;
    solve_subproblem(0);
    printf("%d\n",ans);
}

bool input(){
    if(scanf("%d%d",&N,&K)!=2||N+K==0)return false;
    for(int i=0;i<=N;i++)G[i].clear();
    for(int i=0;i<N-1;i++){
        int u,v;
        int c;
        scanf("%d%d",&u,&v);
        scanf("%d",&c);
        u--,v--;
        G[u].push_back(edge(v,c));
        G[v].push_back(edge(u,c));
    }
    return true;
}

int main(){
    while(input()){
        ans=0;
        memset(subtree_size,0,sizeof(subtree_size));
        memset(centroid,0,sizeof(centroid));
        solve();
    }
    return 0;
}

 

posted @ 2015-10-20 15:09  好地方bug  阅读(226)  评论(0编辑  收藏  举报