【Question Solution】P4178 Tree

Front cheese

P3806 [Template] Divide and conquer 1 point . But the data is really good. The first time I opened the array to a small size, it passed; the second time I didn't find the center when I divided and conquered , it was passed... So I can also do P4149 Race .

Title

It is similar to the point divide and conquer template: find the distance on the tree is less than or equal to kkThe number of k paths. (Change the template equal to less than or equal, and need to count the number of paths)

analysis

Since the question has become less than or equal to, then we can no longer use the original method of opening the barrel. So we consider a statistical scheme to pull out the nodes in all subtrees of the current root.

The specific method is to sort the nodes in all subtrees according to the distance to the root, and then start double pointer O (n) O(n) at both endsO ( n ) scan. (G oogle Googlewithout double pointerGoogle


So you made a confident shot, only to find it burst 0 00 ! ! !

In fact, there are some circumstances that have not been considered.

Since the ordinary point divide and conquer is to perform answer statistics on each subtree of the root, it means that the statistical path is between different subtrees, but we pulled all the points out and sorted this time There is no guarantee that this path spans two subtrees. Then the following picture will be produced:

V24JYV.png

Although the blue path passes through the root node on the way, it is obviously an illegal path and needs to be subtracted.

A little tolerance is used here. Since this illegal path must be in the same subtree as the root node, we first calculate the number of paths passing through the root of this subtree (the root of the subtree in the figure above is 1), and then subtract it. For illegal situations in the subtree, we can then use the same method to exclude them.

Note: The time of inclusion and exclusion is not when the answer of the child node is actually counted. Before the calculation, the son’s dis dis is needed.The d i s value is set as the edge weight from the current root node to it, because such an illegal path will definitely reach the root node, and the redundant edge that has passed twice must be subtracted in the statistics.

Code

#include <bits/stdc++.h>
#define MAX 100005
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

int n, k, cnt, rt, sum, tot;
int head[MAX], vet[MAX], Next[MAX], cost[MAX];
int dis[MAX], d[MAX], mx[MAX], sz[MAX], vis[MAX];
ll ans;

void add(int x, int y, int w){
    
    
    cnt++;
    Next[cnt] = head[x];
    head[x] = cnt;
    vet[cnt] = y;
    cost[cnt] = w;
}

void getrt(int x, int fa){
    
    		//找重心(点分治模板)
    sz[x] = 1, mx[x] = 0;
    for (int i = head[x]; i; i = Next[i]) {
    
    
        int v = vet[i];
        if(v == fa || vis[v]) continue;
        getrt(v, x);
        sz[x] += sz[v];
        mx[x] = max(mx[x], sz[v]);
    }
    mx[x] = max(mx[x], sum-sz[x]);
    if(mx[x] < mx[rt]) rt = x;
}

void getdis(int x, int fa){
    
    		//处理距离(模板)
    d[++tot] = dis[x];
    for (int i = head[x]; i; i = Next[i]) {
    
    
        int v = vet[i];
        if(v == fa || vis[v]) continue;
        dis[v] = dis[x]+cost[i];
        getdis(v, x);
    }
}

ll calc(int x, int w){
    
    		//计算贡献
    tot = 0;
    dis[x] = w;
    getdis(x, 0);		//处理出距离并排序
    sort(d+1, d+tot+1);
    int l = 1, r = tot;
    ll res = 0;
    while(l < r){
    
    		//双指针,从两头开始扫
        if(d[l]+d[r] <= k){
    
    
            res += r-l;
            l++;
        }
        else r--;
    }
    return res;
}

void solve(int x){
    
    
    vis[x] = 1;
    ans += calc(x, 0);
    for (int i = head[x]; i; i = Next[i]) {
    
    
        int v = vet[i];
        if(vis[v]) continue;
        ans -= calc(v, cost[i]);		//容斥,把儿子节点dis初值设为边权
        sum = sz[v];
        rt = 0, mx[rt] = INF;
        getrt(v, 0);
        solve(rt);
    }
}

int main()
{
    
    
    cin >> n;
    int x, y, w;
    for (int i = 1; i < n; ++i) {
    
    
        scanf("%d%d%d", &x, &y, &w);
        add(x, y, w);
        add(y, x, w);
    }
    cin >> k;
    mx[rt] = sum = n;
    getrt(1, 0);
    solve(rt);

    cout << ans << endl;

    return 0;
}

Guess you like

Origin blog.csdn.net/qq_30115697/article/details/91490399