BZOJ1468 Tree

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1468

一道水题,好久没有打点分治了有点手生。

犯了傻,打错了 addedge 调了1h。

基本思路就是按层分治,不超过 O(logn) 层,每一层 O(n) 或者 O(logn) 根据主定理 T(n) = T(n/2) + O(nlogn)

复杂度 O(nlog^2n) 。

此题在统计路径时还要注意容斥,要减去多余的路径。(具体看紫书即可)

#include <cstdio>
#include <cstring>
#include <algorithm>

#define N 50010
#define LL long long

using namespace std;

struct edge{
    int x,to,v;
}E[N<<1];

int n,g[N],K,totE,ansv;

inline void addedge(int x,int y,int v){
    E[++totE]=(edge){y,g[x],v}; g[x]=totE;
    E[++totE]=(edge){x,g[y],v}; g[y]=totE;
}

#define p E[i].x

namespace Tree_Dc{
    int siz[N],root,f[N],totn,a[N],d[N],tot;
    bool v[N];
    
    void Find_Hea(int x,int ft){
        siz[x]=1; f[x]=0;
        for(int i=g[x];i;i=E[i].to)
            if(ft!=p&&!v[p]){
                Find_Hea(p,x);
                siz[x]+=siz[p];
                f[x]=max(f[x],siz[p]);
            }
        f[x]=max(f[x],totn-siz[x]);
        if(!root||f[x]<f[root])
            root=x;
    }
    
    inline int Root(int x){
        root=0; totn=siz[x];
        Find_Hea(x,x);
        return root;
    }
    
    void dfs(int x,int ft){
        a[++tot]=d[x];
        for(int i=g[x];i;i=E[i].to)
            if(!v[p]&&p!=ft){
                d[p]=d[x]+E[i].v;
                dfs(p,x);
            }
    }
    
    inline int count_path(int x,int v){
        d[x]=v; tot=0;
        dfs(x,0);
        sort(a+1,a+tot+1);
        int ans=0,tmp=1;
        for(int i=2;i<=tot;i++){
            while(tmp<i&&a[i]+a[tmp+1]<=K) tmp++;
            while(tmp&&a[i]+a[tmp]>K) tmp--;
            ans+=min(tmp,i-1);
        }
        return ans;
    }
    
    void DC(int x){
        int tmp=ansv;
        ansv+=count_path(x,0);
        v[x]=1;
        for(int i=g[x];i;i=E[i].to)
            if(!v[p]){
                ansv-=count_path(p,E[i].v);
                DC(Root(p));
            }
    }
}

int main(){
    freopen("test.in","r",stdin);
    scanf("%d",&n);
    for(int i=1,x,y,v;i<n;i++){
        scanf("%d%d%d",&x,&y,&v);
        addedge(x,y,v);
    }
    scanf("%d",&K);
    Tree_Dc::siz[1]=n;
    Tree_Dc::DC(Tree_Dc::Root(1));
    printf("%d\n",ansv);
    return 0;
}
Code

 

posted @ 2015-06-03 15:28  lawyer'  阅读(145)  评论(0编辑  收藏  举报