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


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

    -------------------------------------------------------------------------

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
     
    using namespace std;
     
    typedef long long ll;
     
    const int maxn = 100009;
     
    int N, M, K, e_u, e_v, n, Rt, T, _T, len;
    int par[maxn], sz[maxn], mx[maxn], nxt[maxn];
    bool vis[maxn];
    ll ans;
     
    template<class T>
    inline void Max(T &x, T t) {
    if(t > x) x = t;
    }
     
    inline int getint() {
    char c = getchar();
    for(; !isdigit(c); c = getchar());
    int ret = 0;
    for(; isdigit(c); c = getchar())
    ret = ret * 10 + c - '0';
    return ret;
    }
     
    struct edge {
    int t;
    edge* n;
    } E[maxn << 1], *pt = E, *H[maxn];
     
    inline void AddEdge(int u, int v) {
    pt->t = v, pt->n = H[u], H[u] = pt++;
    }
     
    void dfs_rt(int x, int fa = -1) {
    mx[x] = sz[x] = 1;
    for(edge* e = H[x]; e; e = e->n) if(e->t != fa && !vis[e->t]) {
    dfs_rt(e->t, x);
    sz[x] += sz[e->t];
    Max(mx[x], sz[e->t]);
    }
    Max(mx[x], n - sz[x]);
    if(Rt < 0 || mx[x] < mx[Rt]) Rt = x;
    }
     
    void dfs_sz(int x, int fa = -1) {
    sz[x] = 1;
    for(edge* e = H[x]; e; e = e->n) if(e->t != fa && !vis[e->t]) {
    dfs_sz(e->t, x);
    sz[x] += sz[e->t];
    }
    }
     
    struct BIT {
    int B[maxn], mk[maxn];
    BIT() {
    memset(B, 0, sizeof B);
    }
    inline void Add(int p, int c) {
    for(; p <= N; p += p & -p) if(mk[p] != c) {
    B[p] = 1;
    mk[p] = c;
    } else
    B[p]++;
    }
    inline int Sum(int p, int c) {
    if(p < 0) return 0;
    int ret = 0;
    for(; p; p -= p & -p)
    if(mk[p] == c) ret += B[p];
    return ret;
    }
    inline int Query(int l, int r, int c) {
    return Sum(r, c) - Sum(l - 1, c);
    }
    } A, B, *CUR[2];
     
    void dfs_add(int v, int t, int x, int d, int fa = -1) {
    CUR[v]->Add(d++, t);
    for(edge* e = H[x]; e; e = e->n)
    if(e->t != fa && !vis[e->t]) dfs_add(v, t, e->t, d, x);
    }
     
    void Solve(int x) {
    Rt = -1;
    dfs_rt(x);
    vis[x = Rt] = true;
    dfs_sz(x);
    for(edge* e = H[x]; e; e = e->n) if(!vis[e->t]) {
    dfs_add(0, ++T, e->t, 1);
    for(int i = 1; i <= sz[e->t]; i++)
    ans += ll(CUR[0]->Query(i, i, T)) * CUR[1]->Query(K - i, N, Rt);
    dfs_add(1, Rt, e->t, 2);
    }
    ans += CUR[1]->Query(K, N, Rt);
    for(edge* e = H[x]; e; e = e->n) if(!vis[e->t]) {
    n = sz[e->t];
    Solve(e->t);
    }
    }
     
    bool DFS_C(int x, int fa = -1) {
    for(edge* e = H[x]; e; e = e->n) if(e->t != fa) {
    nxt[e->t] = x;
    if(e->t == e_v) {
    len = 2;
    return true;
    }
    if(DFS_C(e->t, x)) {
    len++;
    return true;
    }
    }
    return false;
    }
     

    void calc(int x, int v, int d) {

    vis[x] = true;
    _T++;
    dfs_add(v, _T, x, d, nxt[x]);
    dfs_sz(x, nxt[x]);
    for(int i = d; i <= d + sz[x]; i++)
    ans += ll(CUR[v]->Query(i, i, _T)) * (CUR[v ^ 1]->Query(K - i, N, T));
    dfs_add(v ^ 1, T, x, len - d + 1, nxt[x]);
    if(!vis[nxt[x]])
    calc(nxt[x], v, d - 1);
    }
     
    void Work() {
    CUR[0] = &A, CUR[1] = &B;
    memset(vis, 0, sizeof vis);
    n = N;
    Solve(T = 0);
    if(M < N) {
    cout << ans << endl;
    return;
    }
    A = BIT(), B = BIT();
    CUR[0] = &A, CUR[1] = &B;
    T = _T = 0;
    DFS_C(e_u);
    nxt[e_u] = e_v;
    ++T;
    memset(vis, 0, sizeof vis);
    vis[e_v] = true;
    dfs_add(0, T, e_v, 1, nxt[e_v]);
    calc(nxt[e_v], 1, len - 1);
    cout << ans << " ";
    }
     
    int Find(int x) {
    return x == par[x] ? x : par[x] = Find(par[x]);
    }
     
    void Init() {
    N = getint(), M = getint(), K = getint();
    for(int i = 0; i < N; i++) par[i] = i;
    for(int i = 0; i < M; i++) {
    int u = getint() - 1, v = getint() - 1;
    int _u = Find(u), _v = Find(v);
    if(_u != _v) {
    par[_u] = _v;
    AddEdge(u, v);
    AddEdge(v, u);
    } else
    e_u = u, e_v = v;
    }
    ans = 0;
    }
     
    int main() {
    Init();
    Work();
    return 0;
    }

    -------------------------------------------------------------------------

    3648: 寝室管理

    Time Limit: 40 Sec  Memory Limit: 512 MB
    Submit: 136  Solved: 67
    [Submit][Status][Discuss]

    Description

        T64有一个好朋友,叫T128。T128是寄宿生,并且最近被老师叫过去当宿管了。宿管可不是一件很好做的工作,碰巧T128有一个工作上的问题想请T64帮忙解决。
      T128的寝室条件不是很好,所以没有很多钱来装修。礼间寝室仅由n-1条双向道路连接,而且任意两间寝室之间都可以互达。最近,T128被要求对一条路径上的所有寝室进行管理,这条路径不会重复经过某个点或某条边。但他不记得是哪条路径了。他只记得这条路径上有不少于k个寝室。于是,他想请T64帮忙数一下,有多少条这样的路径满足条件。
        嗯…还有一个问题。由于最近有一些熊孩子不准晚上讲话很不爽,他们决定修筑一条“情报通道”,如果通道建成,寝室就变成了一个N个点N条边的无向图。并且,经过“情报通道”的路径也是合法的。T128心想:通道建成之前,T64还有一个高效的算法帮我数路径条数,但是通道建成之后,他还有办法吗?对,T64手忙脚乱,根本数不清有多少条路径。于是他找到了你。

    Input

       第一行为三个正整数N,M,K(2 ≤ K ≤ N),代表有n间寝室,m条边连接它们n-1 ≤ m ≤ N;m= n-1意味着“情报遁道”未被修好;m=n意味着“情报通道”已被修好),以及题目描述中的K。
      接下来m行,每行两个正整数z,y,代表第x间寝室与第y间寝室之间有一条双向边。

    Output

      
    仅包含一个整数,代表经过至少K间寝室的路径条数。

    Sample Input

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

    Sample Output

    20

    HINT



    N≤100000      

    K≤N

    M=N           

    Source

  • 相关阅读:
    C#验证类(使用正则表达式)
    SQL数据库还原语句
    JS键盘或鼠标事件
    列表针对列宽度自动调整显示内容,超长以...缩写结尾
    SQL按照日、周、月、年统计数据 (转自BLEACH的blog)
    SQL利用Case When Then多条件判断
    调用Web服务:请求因HTTP状态401失败:Unauthorized
    IFrame自动适应宽高,去掉空白
    Asp调用WebService事例
    Timer不执行Elapsed事件的解决办法
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5188030.html
Copyright © 2020-2023  润新知