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
*/

时间: 2025-01-02 13:14:59

bzoj3648 寝室管理的相关文章

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

好题..写了两个半小时hh,省选的时候要一个半小时内调出这种题目还真是难= = 题目大意是给一棵树或环套树,求点距大于等于K的点对数 这里的树状数组做了一点变换.不是向上更新和向下求和,而是反过来,所以求和的时候sum(k)实际上是求k到n的和 所以我们要求大于等于k的dis的次数和,就是求sum(1,k-1),注意k要减一 如果是树,就是常规的点分治,然后用树状数组维护dis[t]出现的次数 如果是环套树,找环之后割掉一条边,然后先求这棵树的答案.接着考虑过了这条割掉的边s--t的情况:我们以

【BZOJ3648】寝室管理 树分治

[BZOJ3648]寝室管理 Description T64有一个好朋友,叫T128.T128是寄宿生,并且最近被老师叫过去当宿管了.宿管可不是一件很好做的工作,碰巧T128有一个工作上的问题想请T64帮忙解决.T128的寝室条件不是很好,所以没有很多钱来装修.礼间寝室仅由n-1条双向道路连接,而且任意两间寝室之间都可以互达.最近,T128被要求对一条路径上的所有寝室进行管理,这条路径不会重复经过某个点或某条边.但他不记得是哪条路径了.他只记得这条路径上有不少于k个寝室.于是,他想请T64帮忙数

【BZOJ-3648】寝室管理 环套树 + 树状数组 + 点分治

3648: 寝室管理 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 239  Solved: 106[Submit][Status][Discuss] Description T64有一个好朋友,叫T128.T128是寄宿生,并且最近被老师叫过去当宿管了.宿管可不是一件很好做的工作,碰巧T128有一个工作上的问题想请T64帮忙解决.  T128的寝室条件不是很好,所以没有很多钱来装修.礼间寝室仅由n-1条双向道路连接,而且任意两间寝室之间都可以互

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

1棵树的话, 点分治+你喜欢的数据结构(树状数组/线段树/平衡树)就可以秒掉, O(N log^2 N). 假如是环套树, 先去掉环上1条边, 然后O(N log^2 N)处理树(同上); 然后再O(N log N)计算经过删掉边的路径数(在环上扫一遍, 数据结构维护). ------------------------------------------------------------------------- #include<cstdio> #include<cctype>

『寝室管理 基环树点分』

寝室管理 Description T64有一个好朋友,叫T128.T128是寄宿生,并且最近被老师叫过去当宿管了. 宿管可不是一件很好做的工作,碰巧T128有一个工作上的问题想请T64帮忙解决.T128的寝室条件不是很好,所以没有很多钱来装修.礼间寝室仅由n-1条双向道路连接,而且任意两间寝室之间都可以互达.最近,T128被要求对一条路径上的所有寝室进行管理,这条路径不会重复经过某个点或某条边.但他不记得是哪条路径了.他只记得这条路径上有不少于k个寝室.于是,他想请T64帮忙数一下,有多少条这样

Windows Server 2012活动目录基础配置与应用(新手教程)之4---域用户的基本管理

下面分几种方式介绍域用户的创建. 1.图形化界面(前文已介绍) STEP1:以自己的名称新建一个账户(或者使用已存在的账户,以自己的名字命名),按如下示例修改该账户的属性: STEP2:每个人为自己所在宿舍的其他人员创建一个账户.(提示:可以复制账户)分析这种方式的优缺点. 2.利用命令方式完成 STEP1:查看dsadd命令帮助信息,从中找到与添加用户有关的指令. STEP2:查看dsadd  user的帮助信息. STEP3:本例中,当前域名为ahgf01.com.cn.下面需要增加名字为u

javaWeb校园宿舍管理解析(三)

前两章主要集成Struts2以及mybatis,并进行的相应的小测试,现在我们来实现整个登录功能,说简单一下,登录功能就是登录页-->发送请求-->action-->dao-->主菜单. Struts2做为一个声明性架构,struts.xml作为他的入口,用来定义动作默认地方,很多企业习惯将功能模块化,然后在引入struts.xml,因为我们这个项目比较简单,我就不模块化了,所有动作都定义在struts.xml中. <?xml version="1.0" 

20110830 寝室物语

亲爱的大学新生们,你們好!今天是你們进入大学的第一天.首先,让我们以最热烈的掌声欢迎你們的到来,希望在这里,你们能感受到如家一般的温暖:希望在这里,你们能度过人生最难忘的四年:希望在這裡,你們能XXOO...好了,说这么多客套话,相信大家肯定都有一个疑问:“你吖,是谁啊?”那么现在,请允许我简单的作一下自我介绍. 大家好,我是这所大学的一座普通的寝室楼,编号3. 性别應該是男吧,因为跟我住一块的都是男生. 年龄保密,不过我建成的时候,你们肯定都还没出生! 体重不详,这个我真不知道,因为没称过…

2018.12.28-dtoj-3648-寝室管理

题目描述: T64有一个好朋友,叫T128.T128是寄宿生,并且最近被老师叫过去当宿管了.宿管可不是一件很好做的工作,碰 巧T128有一个工作上的问题想请T64帮忙解决.T128的寝室条件不是很好,所以没有很多钱来装修.礼间寝室仅由n -1条双向道路连接,而且任意两间寝室之间都可以互达.最近,T128被要求对一条路径上的所有寝室进行管理,这 条路径不会重复经过某个点或某条边.但他不记得是哪条路径了.他只记得这条路径上有不少于k个寝室.于是, 他想请T64帮忙数一下,有多少条这样的路径满足条件.