zoukankan      html  css  js  c++  java
  • 树(点分治)

    题面

    给定一个有N个点(编号0,1,…,N-1)的树,每条边都有一个权值(不超过1000)。

    树上两个节点x与y之间的路径长度就是路径上各条边的权值之和。

    求长度不超过K的路径有多少条。

    输入格式

    输入包含多组测试用例。

    每组测试用例的第一行包含两个整数N和K。

    接下来N-1行,每行包含三个整数u,v,l,表示节点u与v之间存在一条边,且边的权值为l。

    当输入用例N=0,K=0时,表示输入终止,且该用例无需处理。

    输出格式

    每个测试用例输出一个结果。

    每个结果占一行。

    数据范围

    N≤10000
    

    输入样例:

    5 4
    0 1 3
    0 2 1
    0 3 2
    2 4 1
    0 0
    

    输出样例:

    8
    

    题解

    板子题, 求完距离, 尺取法

    #include <bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    using namespace std;
    
    const int N = 1e4 + 5;
    
    int n, m, k;
    int h[N], to[N << 1], ne[N << 1], co[N << 1], tot;
    int d[N], b[N];
    int siz[N], mxcen, center;
    int tax[N], cnt[N], ans, v[N];
    
    inline void add(int u, int v, int c)
    {
        ne[++tot] = h[u]; h[u] = tot; co[tot] = c; to[tot] = v;
    }
    
    void dfscen(int x, int f)
    {
        siz[x] = (f != 0);
        int max_center = 0;
        for (int i = h[x]; i; i = ne[i])
        {
            int& y = to[i];
            if (y == f) continue;
            dfscen(y, x);
            siz[x] += siz[y];
            max_center = max(max_center, siz[y]);
        }
        max_center = max(max_center, n - siz[x]);
    
        if (max_center < mxcen)
        {
            mxcen = max_center;
            center = x;
        }
    
        d[center] = 0;
    }
    
    void dfsd(int u, int f, int t)
    {
        b[u] = t;
        for (int i = h[u]; i; i = ne[i])
        {
            int y = to[i];
            if (y == f || v[y]) continue;
            d[y] = d[u] + co[i];
            dfsd(y, u, t == center ? y : t);
        }
    }
    
    bool cmp(int a, int b)
    {
        return d[a] < d[b];
    }
    
    void work(int p, int f)
    {
        memset(cnt, 0, sizeof cnt);
        memset(b, 0, sizeof b);
        mxcen = N + 1; dfscen(p, f);  
        v[center] = 1; dfsd(center, f, center);
    
        int cntx = 0;
        rep(i, 1, n) if (b[i]) tax[++cntx] = i, ++cnt[b[i]];
        sort(tax + 1, tax + 1 + cntx, cmp);
    
        for (int l = 1, r = cntx; l < r; --cnt[b[tax[l++]]])
        {
            while (r > l && d[tax[l]] + d[tax[r]] > k) --cnt[b[tax[r--]]];
            ans += r - l - cnt[b[tax[l]]] + 1;
        }
    
        for (int i = h[center], c = center; i; i = ne[i])
            if (ne[h[to[i]]] && v[to[i]] == 0) work(to[i], c);
    }
    
    int main()
    {
        ios::sync_with_stdio(0); cin.tie(0);
        while (cin >> n >> k, n + k)
        {
            memset(h, 0, sizeof h); tot = ans = 0;
            memset(v, 0, sizeof v);
            rep(i, 2, n)
            {
                int u, v, c; cin >> u >> v >> c;
                add(u + 1, v + 1, c);
                add(v + 1, u + 1, c);
            }
            work(1, 0);
            cout << ans << '
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    buildroot编译文件系统,出现mount: you must be root. can't open /dev/console: Permission denied这种错误。
    Ubuntu 18.04实现实时显示网速
    git 第一次push 出现fatal: 无法读取远程仓库。
    Sql2012 AlwaysOn
    SCVMM 安装
    POJ 3537 Crosses and Crosses
    HDOJ 1524 A Chess Game
    HDOJ 1907 John
    HDOJ 1848 Fibonacci again and again
    HDOJ 1536 S-Nim
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/13071084.html
Copyright © 2011-2022 走看看