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

【POJ1741】Tree

时间:2018-11-06 00:47:43      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:else   size   ons   分治策略   class   namespace   algo   题目   ace   

题目大意:给定一棵 N 个节点的无根树,边有边权,统计树上边权和不大于 K 的路径数。

对于每条树上路径,对于每一个点来说,该路径只有经过该点和不经过该点两种情况,对于不经过该点的情况,可以转化成是否经过以该点为树根的子树节点的子问题,由此构成一个分治策略。

对于点分治来说,限制算法复杂度的瓶颈之一是递归的层数,即:子问题的数目。因此,为了避免树退化成一条链,应该每次选取一棵树的重心作为根节点,进行递归求解。层数可以控制在 \(O(logn)\) 级别。

在统计经过每一个点的路径数量时,应该从答案中减去没有经过该点的路径数量,即:减去路径端点在同一棵子树的答案贡献值。

代码如下

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define cls(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1e4+10;
const int inf=0x3f3f3f3f;

inline int read(){
    int x=0,f=1;char ch;
    do{ch=getchar();if(ch==‘-‘)f=-1;}while(!isdigit(ch));
    do{x=x*10+ch-‘0‘;ch=getchar();}while(isdigit(ch));
    return f*x;
}

struct node{
    int nxt,to,w;
}e[maxn<<1];
int tot=1,head[maxn];
inline void add_edge(int from,int to,int w){
    e[++tot].nxt=head[from],e[tot].to=to,e[tot].w=w,head[from]=tot;
}

int n,k,sn,root,ans,cnt,size[maxn],f[maxn],deep[maxn],d[maxn],vis[maxn];

void read_and_parse(){
    for(int i=1;i<n;i++){
        int from=read(),to=read(),val=read();
        add_edge(from,to,val),add_edge(to,from,val);
    }
}

void get_root(int u,int fa){
    size[u]=1,f[u]=0;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;if(vis[v]||v==fa)continue;
        get_root(v,u);
        f[u]=max(f[u],size[v]);
        size[u]+=size[v];
    }
    f[u]=max(f[u],sn-size[u]);
    if(f[u]<f[root])root=u;
}

void get_deep(int u,int fa){
    deep[++cnt]=d[u];
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;if(v==fa||vis[v])continue;
        d[v]=d[u]+e[i].w;
        get_deep(v,u);
    }
}

int calc(int u,int now){
    d[u]=now,cnt=0;
    get_deep(u,0);
    sort(deep+1,deep+cnt+1);
    int l=1,r=cnt,src=0;
    while(l<r){
        if(deep[l]+deep[r]<=k)src+=r-l,++l;
        else --r;
    }
    return src;
}

void dfs(int u){
    ans+=calc(u,0),vis[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;if(vis[v])continue;
        ans-=calc(v,e[i].w);
        sn=size[v];
        root=0,get_root(v,0);
        dfs(root);
    }
}

void solve(){
    sn=n,root=0,f[0]=inf;
    get_root(1,0);
    dfs(root);
    printf("%d\n",ans);
}

void init(){
    cls(vis,0);cls(head,0);
    tot=1,ans=0,root=0;
}

int main(){
    while(1){
        init();
        n=read(),k=read();
        if(!(n+k))break;
        read_and_parse();
        solve();
    }
    return 0;
}

【POJ1741】Tree

标签:else   size   ons   分治策略   class   namespace   algo   题目   ace   

原文地址:https://www.cnblogs.com/wzj-xhjbk/p/9912367.html

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