bzoj3648 寝室管理

Posted 逢山开路 遇水架桥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3648 寝室管理相关的知识,希望对你有一定的参考价值。

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3648

【题解】

明天就要去ctsc/apio了有点小激动啊(题解无关

这道题如果是树就是一个裸的点分治+BIT啦!

环套树啊。。去掉环上一条边,点分+BIT算一下。

然后考虑通过这条边,一定是某点环套树-》边-》某点环套树

一遍扫环BIT计算即可。

这样例神坑啊。。少了个2

真正的样例可以看程序最后(答案没错)

技术分享
# include <stdio.h>
# include <string.h>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 2e5 + 10;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, m, K;
int head[M], nxt[M], to[M], tot=1; bool del[M];
inline void add(int u, int v) {
    ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
}
inline void adde(int u, int v) {
    add(u, v), add(v, u);
}

ll ans = 0;

// ================== BIT =================== //
namespace BIT {
    const int M = 6e5 + 10;
    int c[M], n;
    # define lb(x) (x&(-x))
    inline void init(int _n) {
        n = _n;
        memset(c, 0, sizeof c);
    }
    inline void edt(int x, int d) {
        for (; x<=n; x+=lb(x)) c[x] += d;
    }
    inline int sum(int x) {
        int ret = 0;
        for (; x; x-=lb(x)) ret += c[x];
        return ret;
    }
    inline int sum(int x, int y) {
        return sum(y) - sum(x-1);
    }
    # undef lb
}

// ================== dfz =================== //
int sz[M], mx[M];
bool vis[M];
inline void getsz(int x, int fa=0) {
    sz[x] = 1, mx[x] = 0;
    for (int i=head[x]; i; i=nxt[i]) {
        if(del[i] || to[i] == fa || vis[to[i]]) continue;
        getsz(to[i], x);
        sz[x] += sz[to[i]];
        if(sz[to[i]] > mx[x]) mx[x] = sz[to[i]];
    }
}

int mi, centre;
inline void getcentre(int x, int tp, int fa=0) {
    if(sz[tp] - sz[x] > mx[x]) mx[x] = sz[tp] - sz[x];
    if(mx[x] < mi) mi = mx[x], centre = x;
    for (int i=head[x]; i; i=nxt[i]) {
        if(del[i] || to[i] == fa || vis[to[i]]) continue;
        getcentre(to[i], tp, x);
    }
}

inline void getans(int x, int d, int fa=0) {
    ans += BIT::sum(max(1, K-d-1), n);
    for (int i=head[x]; i; i=nxt[i]) {
        if(del[i] || to[i] == fa || vis[to[i]]) continue;
        getans(to[i], d+1, x);
    }
}

inline void addans(int x, int d, int fa=0) {
    BIT::edt(d, 1);
    for (int i=head[x]; i; i=nxt[i]) {
        if(del[i] || to[i] == fa || vis[to[i]]) continue;
        addans(to[i], d+1, x);
    }
}
    
inline void delans(int x, int d, int fa=0) {
    BIT::edt(d, -1);
    for (int i=head[x]; i; i=nxt[i]) {
        if(del[i] || to[i] == fa || vis[to[i]]) continue;
        delans(to[i], d+1, x);
    }
}


inline void dfz(int x) {
    getsz(x); mi = n;
    getcentre(x, x);
    x = centre;
    // do something
    for (int i=head[x]; i; i=nxt[i]) {
        if(del[i] || vis[to[i]]) continue;
        getans(to[i], 1, x);
        addans(to[i], 1, x);
    }
    ans += BIT::sum(K-1, n);
    for (int i=head[x]; i; i=nxt[i]) {
        if(del[i] || vis[to[i]]) continue;
        delans(to[i], 1, x);
    }
    vis[x] = 1;
    for (int i=head[x]; i; i=nxt[i]) {
        if(del[i] || vis[to[i]]) continue;
        dfz(to[i]);
    }
} 

inline void solve_dfz() {
    memset(vis, 0, sizeof vis);
    BIT::init(n); dfz(1);
}

int st[M], stn, c[M], cn;
inline void dfs_circle(int x, int fa=0) {
    if(cn) return;
    if(vis[x]) {
        for (int i=stn; st[i]!=x; --i) c[++cn] = st[i];
        c[++cn] = x;
        return ;
    }
    st[++stn] = x;
    vis[x] = 1; 
    for (int i=head[x]; i; i=nxt[i]) {
        if(to[i] == fa) continue;
        dfs_circle(to[i], x);
    }
    --stn;
}

int d[M], dn=0;
inline void getdis(int x, int dis, int fa=0) {
    d[++dn] = dis;
    for (int i=head[x]; i; i=nxt[i]) {
        if(to[i] == fa || del[i] || vis[to[i]]) continue;
        getdis(to[i], dis+1, x);
    }
}

inline void solve() {
    stn = cn = 0;
    dfs_circle(1);
//    printf("%d\n", cn);
//    for (int i=1; i<=cn; ++i) printf("%d ", c[i]);
//    puts("");
    for (int i=head[c[1]]; i; i=nxt[i]) {
        if(to[i] == c[cn]) {
            del[i] = 1; del[i^1] = 1;
            break;
        }
    }
    solve_dfz();
    // cross c[cn]->c[1]
//    printf("%lld\n", ans);
    BIT::init(n);
    memset(vis, 0, sizeof vis);
    for (int i=1; i<=cn; ++i) vis[c[i]] = 1;
    for (int i=1; i<=cn; ++i) {
        dn = 0;
        getdis(c[i], 0);
        for (int j=1; j<=dn; ++j) ans += BIT::sum(max(1, K-(cn-i+1)-d[j]), n);
        for (int j=1; j<=dn; ++j) BIT::edt(d[j]+i, 1);
    }
    printf("%lld\n", ans);
}

int main() {
    scanf("%d%d%d", &n, &m, &K);
    for (int i=1, u, v; i<=m; ++i) {
        scanf("%d%d", &u, &v);
        adde(u, v);
    }
    if(n == m) solve();
    else solve_dfz(), printf("%lld\n", ans);
    return 0;
}
/*
5 5 2
1 3
2 4
3 5
4 1
5 2
*/
View Code

 

以上是关于bzoj3648 寝室管理的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3648: 寝室管理( 点分治 + 树状数组 )

bzoj3648: 寝室管理(环套树+点分治)

2018.12.28-dtoj-3648-寝室管理

BZOJ3675 & 洛谷3648 & UOJ104:[Apio2014]序列分割——题解

费用流BZOJ1877[SDOI2009]-晨跑

BZOJ1877晨跑(费用流)