点分治:统计长度为K的路径条数

来源:互联网 发布:淘宝鲁班系统 编辑:程序博客网 时间:2024/04/26 20:31

套用第一种点分治模板——先加后减法。
计算过程略微不同,得到deep数组后,计算和为K的路径对数
1.剔除d[i]+d[i]==K的情况
2.遍历一遍后,每种情况计算了两次,最后需要除2

#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#include<limits.h>#include<queue>#include<vector>#define ll long long#define MP make_pair#define MP(x,y) make_pair((x),(y))#define X first#define Y second#define oo 0x3f3f3f3fconst ll INF = 0x0fffffffffffffff;using namespace std;typedef long long lld;const int maxn = 10000+10;int n,K;typedef pair<int,int> F;vector<F> e[maxn];int s[maxn],deep[maxn],d[maxn],ans;bool vis[maxn];void add(int u,int v,int w) { e[u].push_back(MP(w,v)); }F getcore(int u,int f,int sum){    s[u]=1;    int lar=0;    F ans=MP(oo,0);    for(int i=0;i<e[u].size();i++){        int v=e[u][i].Y;        if(v==f||vis[v]) continue;        F x=getcore(v,u,sum);        s[u]+=s[v];        lar=max(lar,s[v]);//记录子树节点的最大值        ans=min(ans,x);//记录子树结果的最小值(权值最小,然后编号最小)    }    lar=max(lar,sum-s[u]);    ans=min(ans,MP(lar,u));    return ans;}void build(){    for(int i=1;i<=n;i++) e[i].clear();    for(int i=1;i<=n;i++){        int v,w;        while(scanf("%d",&v)!=EOF&&v){            scanf("%d",&w);            add(i,v,w),add(v,i,w);        }    }}void getdeep(int u,int f){    deep[++deep[0]]=d[u];    for(int i=0;i<e[u].size();i++){        int v=e[u][i].Y,w=e[u][i].X;        if(v==f||vis[v]) continue;        d[v]=d[u]+w;        getdeep(v,u);    }}int cal(int u,int w){//统计初始长度为w,长度和不大于K的路径个数(可重合)    d[u]=w,deep[0]=0,getdeep(u,-1);//得到以u为根节点,u的初始深度为w,其他点的深度    sort(deep+1,deep+deep[0]+1);    int tmp=0;    for(int i=1;i<=deep[0];i++){        int r=upper_bound(deep+1,deep+deep[0]+1,K-deep[i])-deep;        int l=lower_bound(deep+1,deep+deep[0]+1,K-deep[i])-deep;        tmp+=(r-l);        if(i>=l&&i<r) tmp--;    }    return tmp/2;}void work(int u,int f,int sum){    u=getcore(u,f,sum).Y;    ans+=cal(u,0);    vis[u]=1;    for(int i=0;i<e[u].size();i++){        int v=e[u][i].Y,c=e[u][i].X;        if(vis[v]||v==f) continue;        ans-=cal(v,c);        work(v,u,s[v]);    }}int main(){   // freopen("a.txt","r",stdin);    while(scanf("%d",&n)!=EOF&&n){        build();        scanf("%d",&K);        while(K){            memset(vis,0,sizeof(vis)),ans=0;            work(1,-1,n);            if(ans) printf("AYE\n");            else printf("NAY\n");            scanf("%d",&K);        }        printf(".\n");    }}
0 0
原创粉丝点击