zoukankan      html  css  js  c++  java
  • 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;
    }
    

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

  • 相关阅读:
    UVA297:Quadtrees(四分树)
    hive查询ncdc天气数据
    hadoop-hive查询ncdc天气数据实例
    servlet课堂笔记
    servlet课堂笔记
    代码 c++实现动态栈
    代码 c++实现动态栈
    代码,用c++实现线性链表
    代码,用c++实现线性链表
    后海日记(8)
  • 原文地址:https://www.cnblogs.com/zhouzj2004/p/13748937.html
Copyright © 2011-2022 走看看