POJ

来源:互联网 发布:牛播最新直播室源码 编辑:程序博客网 时间:2024/06/17 12:02

题目:给你一棵n个节点的树,每条边都有一个权值,给你一个K,问你有多少点对(u,v)使得他们之间路径的权值和<=K。((1,2)和(2,1)算一对)

思路:点分治

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#include<string>#include<vector>#include<map>#include<set>#include<queue>#include<stack>#include<list>#include<numeric>using namespace std;#define PI acos(-1.0)#define LL long long#define ULL unsigned long long#define INF 0x3f3f3f3f#define mm(a,b) memset(a,b,sizeof(a))#define PP puts("*********************");template<class T> T f_abs(T a){ return a > 0 ? a : -a; }template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}// 0x3f3f3f3f3f3f3f3f// 0x3f3f3f3fconst int maxn=1e4+50;struct Node{    int v,w,next;}edge[2*maxn];int head[maxn],tol;//节点从1开始计数int son[maxn],f[maxn],vis[maxn];//son表示以i为根的子树大小//f数组表示以u为根的最大子树的大小//vis表示该节点是不是已经作为重心了int dep[maxn],siz,d[maxn];int cntv,root,K,ans;void init(){    mm(head,-1);tol=0;    mm(vis,0);    f[0]=INF;//一定要定义成最大的值}void addedge(int u,int v,int w){    edge[tol].v=v;    edge[tol].w=w;    edge[tol].next=head[u];    head[u]=tol++;}void getroot(int u,int fa){//寻找重心    son[u]=1,f[u]=0;    for(int i=head[u];i!=-1;i=edge[i].next){        int v=edge[i].v;        if(v==fa||vis[v]) continue;        getroot(v,u);        son[u]+=son[v];        f[u]=max(f[u],son[v]);    }    f[u]=max(f[u],cntv-son[u]);//sum表示当前树的大小    if(f[u]<f[root]) root=u;//更新当前重心}void getdepth(int u,int fa){    dep[siz++]=d[u];    for(int i=head[u];i!=-1;i=edge[i].next){        int v=edge[i].v;        if(v==fa||vis[v]) continue;        d[v]=d[u]+edge[i].w;        getdepth(v,u);    }}int cal(int u,int w){    d[u]=w;    siz=0;    getdepth(u,0);    sort(dep,dep+siz);    int l=0,r=siz-1,res=0;    while(l<r){        if(dep[l]+dep[r]<=K){            res+=r-l;            l++;        }        else r--;    }    return res;}void solve(int u){//计算以u为重心的树    ans+=cal(u,0);    vis[u]=1;    for(int i=head[u];i!=-1;i=edge[i].next){        int v=edge[i].v;        if(vis[v]) continue;        ans-=cal(v,edge[i].w);//减去不合法的数目        cntv=son[v];        root=0;        getroot(v,0);        solve(root);    }}int main(){    int n,u,v,w;    while(~scanf("%d%d",&n,&K)){        if(!n&&!K) break;        init();        for(int i=1;i<n;i++){            scanf("%d%d%d",&u,&v,&w);            addedge(u,v,w);            addedge(v,u,w);        }        cntv=n;        root=0;//初始化根        getroot(1,0);        ans=0;        solve(root);        printf("%d\n",ans);    }    return 0;}


原创粉丝点击