POJ - 1741 partition entry point

Topic link: http: //poj.org/problem id = 1741?
Subject to the effect:

Given a tree with n points of
interrogation from the tree to the number of points <= k a.

Dotted rule, is an excellent tool for processing a tree path.
If you need to deal with large-scale general tree path, dotted rule is a good choice.

I came here to talk about my own point of divide and conquer a little understanding and perception (to help novice into the pit ......)
to start now!

1. The basic idea of partition point
point divide and conquer, divide and conquer by definition is carried out based on the node tree.
If we dig a little deeper it? For the open point of fact, to open the tree.
So I think the essence dotted rule is actually a tree will be split into a number of subtrees treatment, and ongoing.
It should also point the essence of divide and conquer.

2. Select the partition point
now that we want to be a point of divide and conquer, then the election is certainly the most important.
Consider the following question:
if the tree is reduced to a chain,
we selected chain as the first partition points, the theoretical time complexity?
And if you choose the center of the chain, its theoretical time complexity and how much?
The answer is quite simple.
Select first chain: O (n)
selected chain heart: O (logn)
Through this example, we find that:
if the larger point about sub-tree after the election, the more layers of recursion, the slower time, and vice versa faster.
So our choice of site standards came out, and we have this character called the point: the center of gravity of the tree!

This is a point of partition template title.

Dotted rule generally have the following uses:

Seeking the path points or less in length equal to k (the number of paths);
path length is a multiple of k;
path length k and the minimum number of edges in the path;
path length after a certain number x modulo equal to k;
path after the number of points can not exceed k, and the maximum path length.
 For the path of the tree, it can be divided into two types:

After root root.
Contained in a subtree root, i.e. without root.

Ideas: For this question after obtaining all the child node to the root of the distance, with the opposite sort search. To get the number. Inclusion and exclusion need it because these points could come from the same sub-tree. But to have to come from different sub-trees through the root.

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+20, inf=1e9+1000;

struct edg{
    int to, w, next;
}e[N*4];

int tot, root, ans, allnode, n, k;
int head[N], vis[N], siz[N], d[N];
int deep[N];//路径长度//deep[0]子节点个数
int f[N];//求重心的最多子节点个数

void add(int u, int v, int w){
    e[tot].to=v, e[tot].next=head[u];
    e[tot].w=w, head[u]=tot++;
}

void getroot(int u, int fa){//求重心

    siz[u]=1;
    f[u]=0;
    for(int i=head[u]; i!=-1; i=e[i].next){
        int to=e[i].to;
        if(to==fa||vis[to]){
            continue;
        }
        getroot(to, u);
        siz[u]+=siz[to];
        f[u]=max(f[u], siz[to]);
    }
    f[u]=max(allnode-siz[u], f[u]);
    if(f[u]<f[root]){
        root=u;
    }
}

void getdeep(int u, int fa){//获取子树所有节点与根的距离
    deep[++deep[0]]=d[u];
    for(int i=head[u]; i!=-1; i=e[i].next){
        int to=e[i].to;
        if(to==fa||vis[to]){
            continue;
        }
        d[to]=d[u]+e[i].w;
        getdeep(to, u);
    }
}

int cal(int u, int w){//计算当前以重心x的子树下,所有情况的答案

    d[u]=w, deep[0]=0;
    getdeep(u, 0);
    sort(deep+1, deep+deep[0]+1);
    int ans=0;
    for(int l=1, r=deep[0]; l<r; ){
        if(deep[l]+deep[r]<=k){
            ans+=r-l;
            l++;
        }
        else{
            r--;
        }
    }
    return ans;
}

void work(int u){//以x为重心进行计算
    vis[u]=1;
    ans+=cal(u, 0);
    for(int i=head[u]; i!=-1; i=e[i].next){
        int to=e[i].to;
        if(vis[to]){
            continue;
        }
        ans-=cal(to, e[i].w);//删除在同一棵子树的点对贡献
        
        allnode=siz[to];//继续分治
        root=0;
        getroot(to, u);
        work(root);
    }
}

int main(){

    int u, v, w;
    while(scanf("%d%d", &n, &k), (n+k)){
        memset(head, -1, sizeof(head));
        memset(vis, 0, sizeof(vis));
        tot=1;
        for(int i=1; i<=n-1; i++){
            scanf("%d%d%d", &u, &v, &w);
            add(u, v ,w), add(v, u, w);
        }
        root=ans=0;
        allnode=n, f[0]=inf;
        getroot(1, 0);
        work(root);
        printf("%d\n", ans);

    }

    return 0;
}
Published 374 original articles · won praise 22 · views 20000 +

Guess you like

Origin blog.csdn.net/qq_21433411/article/details/103506984