zoukankan      html  css  js  c++  java
  • [POJ1741]Tree

    我们知道,树上两个点的LCA要么是当前根节点,要么不是。。所以两个点间的最短路径要么经过当前根节点,要么在一棵当前根节点的子树中。。

    考虑点分治,于是在原来同一子树中的两个点必然在一次分治中变为路径经过当前根节点的两个点。

    处理路径经过当前根节点的两个点的情况。对于当前树,每个节点(根节点除外)记录深度(dep_i)(根节点深度为(0))和除当前根节点外的最远祖先(fa_i)。。

    于是有:

    [sum [fa_i e fa_j land dep_i+dep_j le K] ]

    显然,式子等于:

    [sum [dep_i+dep_jle K]-sum[fa_i=fa_jland dep_i+dep_jle K] ]

    于是可以这样解决:

    在当前树中,将(dep)排序,用(l)表示左指针,(r)表示右指针,(l)从左向右遍历。如果(dep_l+dep_rle k),则点对((l,t)(i<tle r))都符合题意,于是将(r-l)加入答案中,并且(l)++;否则(r)--。

    需要注意的是链的情况。。时间复杂度会退化成(O(N^2))。。我们可以将重心作为根,以保证复杂度为(O(Nlog^2N))


    #include<bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 10005;
    
    struct edge {
        int v, l;
        edge(int v_, int l_) :v(v_), l(l_) {};
    };
    
    vector<edge> g[MAXN];
    vector<int> dep;
    int n, k, dist[MAXN], vis[MAXN], f[MAXN], root, ans, s[MAXN], tot;
    
    
    inline void getroot(int now, int fa) {
        int u;
        s[now] = 1, f[now] = 0;
        for (int i = 0; i < g[now].size(); i++) {
            u = g[now][i].v;
            if (u != fa && !vis[u])
                getroot(u, now),
                s[now] += s[u],
                f[now] = max(f[now], s[u]);
        }
        f[now] = max(f[now], tot - s[now]);
        if (f[now] < f[root]) root = now;
    }
    
    inline void getdep(int now, int fa) {
        int u;
        dep.push_back(dist[now]),
        s[now] = 1;
        for (int i = 0; i < g[now].size(); i++) {
            u = g[now][i].v;
            if (u != fa && !vis[u])
                dist[u] = dist[now] + g[now][i].l,
                getdep(u, now),
                s[now] += s[u];
        }
    }
    
    inline int calc(int now, int len) {
        dep.clear(),dist[now] = len;
        getdep(now, 0),
        sort(dep.begin(), dep.end());
        int cnt = 0, l = 0, r = dep.size() - 1;
        while (l < r)
            if (dep[l] + dep[r] <= k) cnt += r - l, l++;
            else r--;
        return cnt;
    }
    
    inline void work(int now) {
        int u;
        ans += calc(now, 0),
        vis[now] = true;
        for (int i = 0; i < g[now].size(); i++) {
            u = g[now][i].v;
            if (!vis[u])
                ans -= calc(u, g[now][i].l),
                f[0] = tot = s[u],
                root = 0,
                getroot(u, 0),
                work(root);
        }
    }
    
    int main() {
        while (~scanf("%d%d",&n,&k)) {
            if (!n && !k) break;
            for (int i = 0; i <= n; i++) g[i].clear();
            memset(vis, 0, sizeof(int)*(n+1));
            int u, v, l;
            for (int i = 1; i < n; i++)
                scanf("%d%d%d",&u,&v,&l),
                g[u].push_back(edge(v, l)),g[v].push_back(edge(u, l));
            f[0] = n,root = 0,tot = n;
            getroot(1, 0),
            ans = 0,
            work(root),
            printf("%d
    ",ans);
        }
    }
    
  • 相关阅读:
    [leetcode-79-Word Search]
    [leetcode-563-Binary Tree Tilt]
    [leetcode-561-Array Partition I]
    [leetcode-556-Next Greater Element III]
    [leetcode-554-Brick Wall]
    [leetcode-557-Reverse Words in a String III]
    [leetcode-532-K-diff Pairs in an Array]
    dev 官网
    DataTable 设置primarykey 后进行 Merge操作
    对称矩阵 一个简单的小把戏
  • 原文地址:https://www.cnblogs.com/QAQAQ/p/10989248.html
Copyright © 2011-2022 走看看