• POJ 1741 树分治


    题目链接【http://poj.org/problem?id=1741】

    题意:

      给出一颗树,然后寻找点对(u,v)&&dis[u][v] < k的对数。

    题解:

      这是一个很经典的树分治的题。假设我们选择了一个参考点u,那么对于不同的点对(u,v),(u , v)之间的路径有两种情况,经过点u,和不经过点u,加入我算出了没有经过点u的对数,然后把经过点u的加起来就是答案了,很简单,这就是分治的思想。具体看代码。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn = 1e4 + 15;
    int N, lit;
    struct Edge
    {
        int to, next, len;
        Edge() {}
        Edge(int to, int next, int len): to(to), next(next), len(len) {}
    } E[maxn * 2];
    int head[maxn], tot;
    void initEdge()
    {
        for(int i = 0; i <= N + 5; i++) head[i] = -1;
        tot = 0;
    }
    void addEdge(int u, int v, int len)
    {
        E[tot] = Edge(v, head[u], len);
        head[u] = tot++;
    
        E[tot] = Edge(u, head[v], len);
        head[v] = tot++;
    }
    int vis[maxn];
    int dep[maxn], L, R;
    int sz[maxn];
    void GetSize(int u, int fa)
    {
        sz[u] = 1;
        for(int k = head[u]; ~k; k = E[k].next)
        {
            int v = E[k].to;
            if(v == fa || vis[v]) continue;
            GetSize(v, u);
            sz[u] += sz[v];
        }
    }
    void GetRoot(int u, int fa, int tot, int &rt)
    {
        int ma = tot - sz[u];
        if(ma > tot / 2) return ;
        for(int k = head[u]; ~k; k = E[k].next)
        {
            int v = E[k].to;
            if(v == fa || vis[v]) continue;
            GetRoot(v, u, tot, rt);
            ma = max(ma, sz[v]);
        }
        if(ma <= tot / 2) rt = u;
    }
    void GetPath(int u, int fa, int len)
    {
        dep[R++] = len;
        for(int k = head[u]; ~k; k = E[k].next)
        {
            int v = E[k].to;
            if(v == fa || vis[v]) continue;
            GetPath(v, u, len + E[k].len);
        }
    }
    int GetNum(int L, int R)
    {
        int ret = 0;
        int pos = R - 1;
        sort(dep + L, dep + R);
        for(int i = L; i < R; i++)
        {
            while(pos > i && dep[i] + dep[pos] > lit) pos--;
            if(pos > i) ret += pos - i;
            else break;
        }
        return ret;
    }
    int GetAns(int u)
    {
        int ret = 0, rt = 0;
        GetSize(u, -1);
        GetRoot(u, -1, sz[u], rt);//找到重心
        vis[rt] = 1;//重心为分界点
        for(int k = head[rt]; ~k; k = E[k].next)
        {
            int v = E[k].to;
            if(vis[v]) continue;
            ret += GetAns(v);//不过rt点的个数
        }
        L = R = 0;
        for(int k = head[rt]; ~k; k = E[k].next)
        {
            int v = E[k].to;
            if(vis[v]) continue;
            GetPath(v, rt, E[k].len);
            ret -= GetNum(L, R);
            L = R;
        }
        ret += GetNum(0, R);
        for(int i = 0; i < R; i++)
            if(dep[i] <= lit) ret++;
            else break;
        vis[rt] = 0;
        return ret;
    }
    int main ()
    {
        while(~scanf("%d %d", &N, &lit))
        {
            if(N == 0 && lit == 0) break;
            initEdge();
            for(int i = 1; i < N; i++)
            {
                int u, v, len;
                scanf("%d %d %d", &u, &v, &len);
                addEdge(u, v, len);
            }
            int ans = GetAns(1);
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    初识python
    文件操作
    初识python
    pycharm IDE
    初识python
    初识Python
    python之网络编程-多线程
    python之并发编程-进程之间的通信
    python之并发编程-多进程
    python之并发编程-操作系统
  • 原文地址:https://www.cnblogs.com/pealicx/p/7506530.html
Copyright © 2020-2023  润新知