• JZOJ 3978. 寝室管理


    Description

    给定一棵由n个点组成的树,或者一棵由n个点组成的有且仅有一个环的“树”。
    求经过不少于k个点的路径数。

    Data Constraint

    (n leq 100000),(k leq n)

    Solution

    树的情况

    点分治即可。
    处理方式有两种:

    Method1

    对于一个分治中心(u),先把(u)以下的所有点抽出来按深度排序,
    那么对于排序后的一个点(i),可以用指针在线性时间复杂度内找到最小的满足条件的点(j)
    (i)的贡献就是(siz[u] - j)
    但是对于(u)的某个儿子(v),以(v)为根的树会算重,所以可以把以(v)为根树内算重的数计算出来减去,
    同样用指针就可以解决,复杂度一样是线性的。

    Method2

    遍历分治中心 (u) 的每棵子树,对于深度 (d),能与它匹配的点的深度就在 (k - d + 1) ~ (n)(设 (u) 的深度为1),
    用一棵线段树就很好维护了。

    带一个环的情况

    先删掉一条环边,然后做一遍点分治。
    那么还需要加上一定经过这条环边的代价。
    假设环是这样子的:

    蓝色边就是删去的环边,现在需要计算一定经过它的路径数。
    具体方法很简单,先将环点1及子树加入数据结构(1的深度为1),然后从 (tot) ~ (2) 做。
    对于点 (i),令它的深度为 (i),然后遍历 (i)(i) 的子树,统计方法类似“Method2”。
    然后令 (i) 的深度为 (tot - i + 2),将 (i)(i) 的子树加入数据结构维护即可。

    路径走出来可能类似这样:

    灵魂画手了...

    思路很简单不赘述正确性。

    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define N 100000
    #define L 100000
    
    #define fo(i, x, y) for(ll i = x; i <= y; i ++)
    #define Fo(i, u) for(ll i = head[u]; i; i = edge[i].next)
    #define lson (t << 1)
    #define rson (t << 1 | 1)
    #define Mes(a, x) memset(a, x, sizeof a)
    #define fd(i, x, y) for(int i = x; i >= y; i --)
    
    #define ll long long
    
    void read(ll &x) {
        char ch = getchar(); x = 0;
        while (ch < '0' || ch > '9') ch = getchar();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
    }
    
    struct EDGE { ll next, to, bz; } edge[N << 2];
    
    ll head[N + 1], cir[N + 1], q[N + 1], siz[N + 1], c[N + 1], vis[N + 1], In[N + 1], used[N + 1];
    
    ll f[N << 3], g[N << 3], now[N << 3];
    
    ll last[N + 1];
    
    ll n, m, K, tot = 0, cnt = 0;
    
    ll cnt_edge = 1;
    void Add(ll u, ll v) { edge[ ++ cnt_edge ] = (EDGE) { head[u], v, 0 }, head[u] = cnt_edge; }
    void Link(ll u, ll v) { Add(u, v), Add(v, u); }
    
    ll tot_h = 0;
    
    void Dfs1(ll u, ll la) {
        siz[u] = c[u] = 1, q[ ++ tot_h ] = u;
        Fo(i, u) if (i != la && ! used[edge[i].to] && ! edge[i].bz) {
            Dfs1(edge[i].to, i ^ 1);
            siz[u] += siz[edge[i].to];
            if (siz[edge[i].to] > c[u])
                c[u] = siz[edge[i].to];
        }
    }
    
    ll Find_heart(ll u, ll la) {
        tot_h = 0;
        Dfs1(u, la);
        fo(i, 1, tot_h) if (siz[u] - siz[q[i]] > c[q[i]])
            c[q[i]] = siz[u] - siz[q[i]];
        ll heart = q[1];
        fo(i, 2, tot_h) if (c[q[i]] < c[heart])
            heart = q[i];
        return heart;
    }
    
    ll Now = 0;
    
    void Updata1(ll t, ll l, ll r) { if (now[t] < Now) g[t] = 0, now[t] = Now; }
    
    void Add1(ll t, ll l, ll r, ll k) {
        Updata1(t, l, r);
        ++ g[t];
        if (l == r) return;
        ll mid = l + r >> 1;
        k <= mid ? Add1(lson, l, mid, k) : Add1(rson, mid + 1, r, k);
    }
    
    ll Max(ll x, ll y) { return x > y ? x : y; }
    
    ll Min(ll x, ll y) { return x < y ? x : y; }
    
    ll Get1(ll t, ll l, ll r, ll x, ll y) {
        Updata1(t, l, r);
        if (x <= l && r <= y) return g[t];
        ll mid = l + r >> 1;
        return (x <= mid ? Get1(lson, l, mid, x, y) : 0) + (y > mid ? Get1(rson, mid + 1, r, x, y) : 0);
    }
    
    ll Dfs2(ll u, ll la, ll dep) {
        ll sum = Get1(1, 1, n, Max(1, K - dep + 1), n);
        Fo(i, u) if (i != la && ! used[edge[i].to] && ! edge[i].bz)
            sum += Dfs2(edge[i].to, i ^ 1, dep + 1);
        return sum;
    }
    
    void Dfs5(ll u, ll la, ll dep) {
        Fo(i, u) if (i != la && ! used[edge[i].to] && ! edge[i].bz)
            Dfs5(edge[i].to, i ^ 1, dep + 1);
       Add1(1, 1, n, Min(dep, n));
    }
    
    ll Dfz(ll u, ll la) {
        used[u] = 1;
        ++ Now; ll sum = 0;
        Add1(1, 1, n, 1);
        Fo(i, u)
            if (i != la && ! used[edge[i].to] && ! edge[i].bz) {
            sum += Dfs2(edge[i].to, i ^ 1, 2);
            Dfs5(edge[i].to, i ^ 1, 2);
        }
        Fo(i, u) if (i != la && ! used[edge[i].to] && ! edge[i].bz)
            sum += Dfz(Find_heart(edge[i].to, i ^ 1), i ^ 1);
        return sum;
    }
    
    int du = 0;
    
    ll Dfs3(ll u, ll la) {
        if (vis[u]) {
            cir[ ++ tot ] = u;
            while (q[tot_h] != u)
                cir[ ++ tot ] = q[tot_h], -- tot_h;
            return 1;
        }
        vis[u] = 1, q[ ++ tot_h ] = u;
        Fo(i, u) if (i != la) {
            if (vis[edge[i].to]) du = i;
            if (Dfs3(edge[i].to, i ^ 1))
                return 1;
        }
        -- tot_h;
        return 0;
    }
    
    void Add2(ll t, ll l, ll r, ll k, ll add) {
        f[t] += add;
        if (l == r) return;
        ll mid = l + r >> 1;
        k <= mid ? Add2(lson, l, mid, k, add) : Add2(rson, mid + 1, r, k, add);
    }
    
    ll Get2(ll t, ll l, ll r, ll x, ll y) {
        if (x <= l && r <= y) return f[t];
        ll mid = l + r >> 1;
        return (x <= mid ? Get2(lson, l, mid, x, y) : 0) + (y > mid ? Get2(rson, mid + 1, r, x, y) : 0);
    }
    
    ll Dfs4(ll u, ll la, ll dep) {
        ll sum = 0;
        sum = Get2(1, 1, L, Max(1, K - dep + 1), L);
        Fo(i, u) if (i != la && ! In[edge[i].to])
            sum += Dfs4(edge[i].to, i ^ 1, dep + 1);
        return sum;
    }
    
    void Dfs6(ll u, ll la, ll dep) {
        Add2(1, 1, L, dep, 1);
        Fo(i, u) if (i != la && ! In[edge[i].to])
            Dfs6(edge[i].to, i ^ 1, dep + 1);
    }
    
    int main() {
        read(n), read(m), read(K);
        for (ll i = 1, x, y; i <= m; i ++)
            read(x), read(y), Link(x, y);
    
        if (n > m) {
            ll ans = Dfz(Find_heart(1, 0), 0);
            printf("%lld
    ", ans); 
        } else {
            tot_h = 0; Dfs3(1, 0);
            edge[du].bz = edge[du ^ 1].bz = 1;
            ll ans = Dfz(Find_heart(1, 0), 0);
            fo(i, 1, tot) In[cir[i]] = 1;
            Add2(1, 1, L, 1, 1);
            Fo(j, cir[1]) if (! In[edge[j].to]) {
                Dfs6(edge[j].to, j ^ 1, 2);
            }
            fd(i, tot, 2) {
                ans += Get2(1, 1, L, Max(1, K - i + 1), L);
                Fo(j, cir[i]) if (! In[edge[j].to]) {
                    ans += Dfs4(edge[j].to, j ^ 1, i + 1);
                }
                Fo(j, cir[i]) if (! In[edge[j].to])
                    Dfs6(edge[j].to, j ^ 1, 2 + (tot - i + 1));
                Add2(1, 1, L, 1 + (tot - i + 1), 1);
            }
            printf("%lld
    ", ans);
        }
    
        return 0;
    }
    

    打了两棵线段树又慢又丑....

  • 相关阅读:
    UOJ.26.[IOI2014]Game(交互 思路)
    Good Bye 2016 F.New Year and Finding Roots(交互)
    Codeforces.835E.The penguin's game(交互 按位统计 二分)
    Codeforces.744B.Hongcow's Game(交互 按位统计)
    Codeforces.862D.Mahmoud and Ehab and the binary string(交互 二分)
    正睿OI 提高 Day1T3 ZYB玩字符串(DP)
    划分vlan
    2三层交换机实现vlan间的路由
    交换机基础-交换机远程telnet
    自动化运维环境的搭建问题处理
  • 原文地址:https://www.cnblogs.com/zhouzj2004/p/13748937.html
Copyright © 2020-2023  润新知