zoukankan      html  css  js  c++  java
  • poj2114 树分治(点分治)

    poj1741板子套一套,统计对数的方式改一下,可以在O(n)时间内统计对数

    最后不要忘记输出最后的“.”

    /*
    给定一棵边权树,是否存在一条路径使得其长度为恰好为x 
    把1741的板子改为求点对之间的距离=k的点对数即可 
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define MAXN 10010
    using namespace std;
    int N,K;
    int ans,root,Max;
    struct node{
        int v,next,w;
    }edge[MAXN<<1];
    int head[MAXN],tot;
    int size[MAXN];
    int maxv[MAXN];
    int vis[MAXN];
    int dis[MAXN];
    int num;
    void init(){
        tot=ans=0;
        memset(head,-1,sizeof head);
        memset(vis,0,sizeof vis);
    }
    void addedge(int u,int v,int w){
        edge[tot].v=v;
        edge[tot].w=w;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    //一次dfs处理子树的大小 
    void dfssize(int u,int f){
        size[u]=1;
        maxv[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(v==f||vis[v]) continue;
            dfssize(v,u);
            size[u]+=size[v];
            if(size[v]>maxv[u])maxv[u]=size[v];
        }
    }
    //一次dfs找重心,这里的r不是重心 
    void dfsroot(int r,int u,int f){
        if(size[r]-size[u]>maxv[u])
            maxv[u]=size[r]-size[u];
        if(maxv[u]<Max) Max=maxv[u],root=u;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(v==f||vis[v]) 
                continue;
            dfsroot(r,v,u);
        } 
    }
    //一次dfs求每个点到重心的距离
    void dfsdis(int u,int d,int f){
        dis[num++]=d;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(v!=f && !vis[v])
                dfsdis(v,d+edge[i].w,u);
        }
    }
    int calc(int u,int d){
        int ret=0;
        num=0;
        dfsdis(u,d,0);//求每个点到根的距离 
        sort(dis,dis+num);
        for (int l=0, r=num-1; l<r; ) {
            if (dis[l] + dis[r] == K) {
                if (dis[l] == dis[r]) {
                    ret += (r-l+1)*(r-l)/2; break;
                }
                int i=l, j=r;
                while (dis[i] == dis[l]) i++;
                while (dis[j] == dis[r]) j--;
                ret += (i-l)*(r-j);
                l = i, r = j;
            } else if (dis[l] + dis[r] < K) l++;
            else r--;
        }
        return ret;
    }
    void dfs(int u){//注意这里的u并不是重心 
        Max=N;
        dfssize(u,0);//求每个子树的规模 
        dfsroot(u,u,0);//求重心 
        ans+=calc(root,0);//求以root为根,dis[u]+dis[v]的点对有多少 
        vis[root]=1;//把这个点从点集删掉 
        for(int i=head[root];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(!vis[v]){
                ans-=calc(v,edge[i].w);
                dfs(v);
            }
        } 
    }
    int main(){
        while(scanf("%d",&N) && N){
            init();
            int v,w;
            for(int i=1;i<=N;i++){
                while(scanf("%d",&v) && v!=0){
                    scanf("%d",&w);
                    addedge(i,v,w);
                    addedge(v,i,w);
                }
            }
            while(scanf("%d",&K) && K!=0){
                memset(vis,0,sizeof vis);
                ans=0;
                dfs(1);
                if(ans) puts("AYE");
                else puts("NAY");
            }
            puts(".");
        }
        return 0;
    } 
  • 相关阅读:
    windows 环境下在anaconda 3中安装python2和python3两个环境(python2和python3共存)
    python 中,如何在一个函数中调用另一个函数返回的多个值中的一个?
    Coursera 机器学习 第一周 学习笔记
    正则表达式 注释
    正则表达式 分组
    24_04SpringMVC实现文件上传及拦截器
    前端之CSS基础
    前端之html
    MySQL数据库实战之优酷
    数据库基础加练习
  • 原文地址:https://www.cnblogs.com/zsben991126/p/9863846.html
Copyright © 2011-2022 走看看