POJ - 1741(树分治)

朴素算法枚举两点为o(n^2) ,若用求树重心 采用分治策略可降至n(logn)^2;

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define INF 100010000
const int maxn = 10100;
int n,d[maxn],K;
struct node{
int to,val;
node(int xx=0,int yy=0):to(xx),val(yy){}
};
vector<node> son[maxn];
bool done[maxn];
int Focus,nown,MIN;
void Get_Focus(int u,int fa){
d[u]=1;
int max_ = 0;
for(int i=0;i<son[u].size();i++) if(son[u][i].to!=fa&&!done[son[u][i].to]){
    int v = son[u][i].to;
    Get_Focus(v,u);
    d[u]+=d[v];
    max_=max(max_,d[v]);
}
max_=max(max_,nown-d[u]);
if(MIN>max_){
    MIN=max_; Focus=u;
}
}

vector<int> V;
int dis[maxn];
void get_distance(int u,int fa){
for(int i=0;i<son[u].size();i++) if(son[u][i].to!=fa&&!done[son[u][i].to]){
    int v=son[u][i].to;
    dis[v]=dis[u]+son[u][i].val;
    V.push_back(dis[v]);
    get_distance(v,u);
}
}

int cal(){
sort(V.begin(),V.end());
int ans=0;
for(int i=0,j=V.size()-1;i<j;){
    if(V[i]+V[j]<=K) ans+=j-i++;
    else j--;
}
return ans;
}
int res;
void dfs(int root){
V.clear();
dis[root]=0; V.push_back(0);
get_distance(root,-1);
res+=cal();
done[root]=true;
for(int i=0;i<son[root].size();i++)if(!done[son[root][i].to]) {
   V.clear();
   int v=son[root][i].to;
   dis[v]=son[root][i].val; V.push_back(dis[v]);
   get_distance(v,root);
   res-=cal();
   nown=V.size();
   MIN=INF; Get_Focus(v,root);
   dfs(Focus);
}
}
int main()
{
    while(scanf("%d %d",&n,&K)==2){
        if(!n&&!K) break;
        for(int i=1;i<=n;i++) son[i].clear();

        int x,y,z;
        for(int i=0;i<n-1;i++){
            scanf("%d %d %d",&x,&y,&z);
            son[x].push_back(node(y,z));
            son[y].push_back(node(x,z));
        }
        memset(done,false,sizeof(done));
        nown=n;
        MIN=INF;
        Get_Focus(1,-1);
        res=0;
        dfs(Focus);
        printf("%d\n",res);
    }
    return 0;
}


你可能感兴趣的:(Algorithm,C++,算法,poj)