zoukankan      html  css  js  c++  java
  • poj 2114 Boatherds (树分治)

    链接:http://poj.org/problem?id=2114

    题意:

    求树上距离为k的点对数量;

    思路:

    点分治。。

    实现代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define inf 0x7fffffff
    const int M = 1e5+10;
    
    struct node{
        int to,next,w;
    }e[M<<2];
    
    int n,m;
    int vis[M],dis[M],d[M],siz[M],f[M],cnt,head[M],sum,root,k,ans;
    
    void init(){
        cnt = 0;
        ans = 0;
        memset(head,0,sizeof(head));
        memset(vis,0,sizeof(vis));
    }
    
    void add(int u,int v,int w){
        e[++cnt].to = v;e[cnt].w = w;e[cnt].next = head[u];head[u] = cnt;
    }
    
    void get_root(int u,int fa){
        siz[u] = 1; f[u] = 0;
        for(int i = head[u];i;i=e[i].next){
            int v = e[i].to;
            if(v != fa&&!vis[v]){
                get_root(v,u);
                siz[u] += siz[v];
                f[u] = max(f[u],siz[u]);
            }
        }
        f[u] = max(f[u],sum - siz[u]);
        if(f[u] < f[root]) root = u;
        return ;
    }
    
    void get_dis(int u,int fa){
        if(d[u] <= k) dis[++dis[0]] = d[u];
        for(int i = head[u];i;i=e[i].next){
            int v = e[i].to;
            if(v != fa&&!vis[v]){
                d[v] = d[u] + e[i].w;
                get_dis(v,u);
            }
        }
        return ;
    }
    
    int cal(int u,int c){
        d[u] = c; dis[0] = 0;
        get_dis(u,0);
        sort(dis+1,dis+dis[0]+1);
        int l = 1,r = dis[0],ans = 0;
        while(l < r){
            if(dis[l] + dis[r] < k) l++;
            else if(dis[l] + dis[r] > k) r--;
            else{
                if(dis[l] == dis[r]){
                    ans += (r-l+1)*(r-l)/2;
                    break;
                }
                else {
                    int i = l,j = r;
                    while(dis[i] == dis[l]) i++;
                    while(dis[j] == dis[r]) j--;
                    ans += (i-l)*(r-j);
                    l = i; r = j;
                }
            }
        }
        return ans;
    }
    
    void solve(int u){
        ans += cal(u,0);
        vis[u] = 1;
        for(int i = head[u];i;i=e[i].next){
            int v = e[i].to;
            if(vis[v]) continue;
            ans -= cal(v,e[i].w);
            sum = siz[v];
            root = 0;
            get_root(v,0);
            solve(root);
        }
    }
    
    int main()
    {
        int u,v,w;
        while(scanf("%d",&n)&&n){
            init();
            for(int i = 1;i <= n;i ++){
                int x,v;
                while(scanf("%d",&x)&&x){
                    scanf("%d",&v);
                    add(i,x,v); add(x,i,v);
                }
            }
            int x;
            while(scanf("%d",&x)&&x){
                memset(vis,0,sizeof(vis));
                k = x; ans = root = 0;
                sum = n; f[0] = inf;
                get_root(1,0);
                solve(root);
                if(ans) printf("AYE
    ");
                else printf("NAY
    ");
            }
            printf(".
    ");
        }
    }
  • 相关阅读:
    设计模式-17-迭代器
    设计模式-16-备忘录
    微服务架构设计
    数据库拆分案例
    生成多个git ssh密钥
    分布式数据中间件TDDL、Amoeba、Cobar、MyCAT架构比较
    maven工程 java 实现文件上传 SSM ajax异步请求上传
    MySQL的分区、分表、集群
    Redis实现分布式锁原理与实现分析
    关于消息队列的使用
  • 原文地址:https://www.cnblogs.com/kls123/p/9729045.html
Copyright © 2011-2022 走看看