码迷,mamicode.com
首页 > 其他好文 > 详细

男人8题之 Tree (pku 1741)(树分治

时间:2015-09-08 18:34:47      阅读:215      评论:0      收藏:0      [点我收藏+]

标签:

题目:求一棵树上路径长度小于k的路径条数。

思路:这是LTC的男人八题里比较简单的一道。首先如果不是树,而是链的话,我们 可以想到一种分治算法(当然链的情况不分治更快),就是对于一个中点,对答案有贡献的要么是跨越中点的路径,要么是两边的路径,那么每次从中点分开,进行 分治的话复杂度是O(nlogn),对于这个树上的情况思路也是一样的,但是树上的分治有个比较特殊的地方是这个中点不太好找,需要跑一次dfs。然后对 每个分开的子树递归计算。我的实现总共用了5个递归,似乎可以少用一个(算子树的节点数目的时候),但是没想清楚怎么去,就索性直接又dfs了一遍。

另外,除了这种点分治,还可以使用边分治,但是边分治有一种难以避免的使复杂度大大增加的情况(处理方法似乎比较复杂),所以树分治的首选还是点分治。

技术分享
/*
* @author:  Cwind
* http://www.cnblogs.com/Cw-trip/
* 蒟蒻只能做几个水题。。
*/
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <set>
#include <cmath>
using namespace std;
#define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
#define pb push_back
#define PB pop_back
#define bk back()
#define fs first
#define se second
#define sq(x) (x)*(x)
#define eps 0.00000001
#define IINF (1<<29)
#define LINF (1ll<<59)
#define INF 1000000000
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> P;

const int maxn=2e4+300;
struct EDGE{
    int to,d;
};
vector<int> G[maxn];
EDGE es[maxn];
int eh;
int center,mins;
bool vis[maxn];
vector<int> dis;
int n,k;
int cnt;
int getCenter(int v,int f){
    int ssum=0,maxs=0;
    for(int i=0;i<G[v].size();i++){
        int e=G[v][i];
        int u=es[e].to;
        if(vis[u]||u==f) continue;
        int aa=getCenter(u,v);
        if(aa>maxs) maxs=aa;
        ssum+=aa;
    }
    if(max(maxs,cnt-ssum-1)<mins){
        center=v;
        mins=max(maxs,cnt-ssum-1);
    }
    return ssum+1;
}
void dfs(int v,int fore,int f){
    dis.pb(fore);
    for(int i=0;i<G[v].size();i++){
        int e=G[v][i];
        int u=es[e].to;
        if(vis[u]||u==f) continue;
        dfs(u,fore+es[e].d,v);
    }
}
void cont(int v,int f){
    cnt++;
    for(int i=0;i<G[v].size();i++){
        int e=G[v][i];
        int u=es[e].to;
        if(vis[u]||u==f) continue;
        cont(u,v);
    }
}
int cul(int v,int fore){
    int ans=0;
    dis.clear();
    dfs(v,fore,-1);
    sort(dis.begin(),dis.end());
    int p=0,q=dis.size()-1;
    while(p<=q){
        while(p<=q&&dis[q]+dis[p]>k) q--;
        if(p>q) break;
        ans+=q-p;
        p++;
    }
    return ans;
}
int solve(int v){
    vis[v]=1;
    int ans=0;
    ans+=cul(v,0);
    for(int i=0;i<G[v].size();i++){
        int e=G[v][i];
        int u=es[e].to;
        if(vis[u]) continue;
        ans-=cul(u,es[e].d);
        mins=1e8;
        cnt=0;
        cont(u,-1);
        getCenter(u,-1);
        ans+=solve(center);
    }
    return ans;
}
void addedge(int from,int to,int d){
    es[eh].to=to,es[eh].d=d;
    G[from].pb(eh++);
    es[eh].to=from,es[eh].d=d;
    G[to].pb(eh++);
}
void init(){
    eh=0;
    for(int i=0;i<=n;i++)
        G[i].clear();
    memset(vis,0,sizeof vis);
    dis.clear();
}
int main(){
    freopen("/home/files/CppFiles/in","r",stdin);
    //freopen("defense.in","r",stdin);
    //freopen("defense.out","w",stdout);
    while(cin>>n>>k){
        if(n==0&&k==0) break;
        init();
        for(int i=0;i<n-1;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            addedge(a,b,c);
        }
        mins=1e9;
        dfs(1,0,-1);
        cnt=0;
        cont(1,-1);
        getCenter(1,-1);
        cout<<solve(center)<<endl;
    }
    return 0;
}
View Code

 

男人8题之 Tree (pku 1741)(树分治

标签:

原文地址:http://www.cnblogs.com/Cw-trip/p/4792421.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!