Algorithmic learning: point divide and conquer

Keywords: PHP


The center of gravity of a tree A point whose size of all subtrees is not more than half the size of the whole tree

[Obtaining the center of gravity] Look for each point in turn. When the maximum subtree of this point is the smallest, it must be the center of gravity.




[Solving problems]

Processing Distance on Graph


n points in a graph, find the number of pairs of points whose distance equals k

The logarithm of n points in a graph whose distance equals the prime number

If there are n points in a graph whose distance is equal to k





Direct recklessness, n^3 complexity, sure explosion

So we need to think of a way to dramatically reduce the complexity, so we use divide and conquer.

Select a node as the root of the DAG and make it a tree.

Imagine holding a root in one hand, shaking it in one hand, and then becoming a tree with several sub-trees under it.


So there are two situations where the distance meets the requirements.

First: Both points are in the same subtree

The second is that two points are in different subtrees, but apparently they all pass through the root node.


So we can calculate the distance from each point to the root node, and then we can find the answer in the time of nlogn by ranking and comparing, which can solve the problem of the second case.


In the first case, we go down to find roots and turn them into trees, and they will both be in different subtrees.

In this way, the first situation will become the second one, and we only need to consider how to deal with the second one and how to turn the first into the second one.


The key to changing the first into the second is the selection of the root. If the root is not selected correctly, it is very likely that a chain will be selected, and then O (n) will be processed to decisively GG.

How to divide and conquer to make the number of layers as small as possible, make the two sides as balanced as possible, and achieve the effect of dichotomy with fewer layers, which can be reduced to logn, so we need to take the center of gravity to do it.

This root is the center of gravity, so the number of layers of the subtree below will be the smallest.




using namespace std;
const int MAXN = 10010;
const int MAXM = 20010;
const int MAXK = 10000010;
struct node
    int to;
    int val;
    int nt;
int  st[MAXN],  ask[110],top;
int  siz[MAXN], f[MAXN], root;
int  dis[MAXN], a[MAXN], S,cnt,n,m;
int  ans[MAXK];
bool vis[MAXN];
void add(int x,int y,int z)
    top++; edge[top] = { y,z,st[x] }; st[x] = top;
void get_root(int x, int fa)
    siz[x] = 1, f[x] = 0;
    for (int i = st[x]; i; i = edge[i].nt)
        int to = edge[i].to;
        if (to == fa || vis[to]) continue;
        get_root(to, x);
        f[x] = max(f[x], siz[to]);
        siz[x] += siz[to];
    f[x] = max(f[x], S - siz[x]);
    if (f[x] < f[root])
        root = x;
void get_dis(int x, int fa,int d)
    dis[++cnt] = a[x];
    for (int i = st[x]; i; i = edge[i].nt)
        int to = edge[i].to;
        if (vis[to] || to == fa) continue;
        a[to] = d + edge[i].val;
        get_dis(to, x,a[to]);
void solve(int x,int len,int w)
    cnt = 0;
    a[x] = len;
    get_dis(x, 0, len);
    for(int i=1;i<=cnt;i++)
        for (int j = 1; j <= cnt; j++)
            if (i != j && dis[i]+dis[j]<MAXK)
                ans[dis[i] + dis[j]] += w;
void divide(int x)
    solve(x, 0, 1);
    vis[x] = 1;
    for (int i = st[x]; i; i = edge[i].nt)
        int to = edge[i].to;
        if (vis[to]) continue;
        solve(to, edge[i].val, -1);
        S = siz[x], root = 0, f[0] = n;
        get_root(to, x);
int main()
    scanf("%d%d", &n, &m);
        for (int i = 1; i <= n-1; i++)
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            add(x, y, z);
            add(y, x, z);
        siz[0] = 0,f[0] = n, root = 0,S=n;
        get_root(1, 0);
        for (int i = 1; i <= m; i++)
            int k;
            scanf("%d", &k);
            if (ans[k])
    return 0;

Posted by ytse on Thu, 10 Oct 2019 12:44:41 -0700