zoukankan      html  css  js  c++  java
  • [BZOJ3653]谈笑风生

    题目描述

    (T)为一棵有根树,我们做如下的定义:

    (a)(b)(T)中的两个不同节点。

    如果(a)(b)的祖先,那么称“(a)(b)不知道高明到哪里去了”。

    (a)(b)(T)中的两个不同节点,如果(a)(b)在树上的距离不超过某个给定常数(x),那么称“(a)(b)谈笑风生”。

    给定一棵(n)个节点的有根树(T),节点的编号为(1)(n),根节点为(1)号节点。你需

    要回答(q)个询问,询问给定两个整数(p)(k),问有多少个有序三元组((a,b,c))满足:

    1. (a,b)(c)为$ T$ 中三个不同的点,且 (a)(p) 号节点;

    2. (a)(b) 都比$ c$不知道高明到哪里去了;

    3. (a)(b) 谈笑风生。这里谈笑风生中的常数为给定的 (k)

    Input

    第一行含有两个正整数(n)(q),分别代表有根树的点数与询问的个数。

    接下来(n-1)行,每行描述一条树上的边。每行含有两个整数(u)(v),代表在节点(u)(v)之间有一条边。

    接下来(q)行,每行描述一个操作。第(i)行含有两个整数,分别表示第(i)个询问的(p)(k)

    (1 le P le N)

    (1 le K le N)

    (N le 300000)

    (Q le 300000)

    Output

    输出 (q) 行,每行对应一个询问,代表询问的答案。

    Sample Input

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

    Sample Output

    3
    1
    3
    

    (dfs)做差,利用树状数组维护。

    我们来考虑一下暴力的做法,我们只用找到所有距离(p)小于等于(k)的所有节点,答案加上节点的(size-1)

    时间复杂度(O(n^2)).

    让我们来考虑优化。

    实际上,我们只用求出距离一个点小于等于(k)(sum size[i]-1),在该节点上方的可以直接算出,我们只用求出所有在它子树内满足条件的点即可。

    我们该如何快速的求出这些点呢?

    我们发现只用离线(dfs)做差维护深度的和即可。

    代码如下

    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <queue>
    #include <iostream>
    #include <algorithm>
     
    using namespace std;
     
    #define LL long long
    #define int long long
    #define u64 unsigned long long
    #define Raed Read
    #define reg register
    #define debug(x) cerr<<#x<<" = "<<x<<endl;
    #define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
    #define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
    #define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
    #define erep(i,G,x) for(reg int i=(G).Head[x]; i; i=(G).Nxt[i])
     
    inline int Read() {
        int res = 0, f = 1;
        char c;
        while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
        do res = (res << 3) + (res << 1) + (c ^ 48);
        while (c = getchar(), c >= 48 && c <= 57);
        return f ? res : -res;
    }
     
    template<class T>inline bool Min(T &a, T const&b) {
        return a > b ? a = b, 1 : 0;
    }
    template<class T>inline bool Max(T &a, T const&b) {
        return a < b ? a = b, 1 : 0;
    }
     
    const int N = 3e5 + 5, M = 3e5 + 5;
    const LL mod = 998244353;
    const int dx[5] = {1, -1, 0, 0, 0}, dy[5] = {0, 0, 0, 1, -1};
    const  double eps = 1e-6;
     
    bool MOP1;
     
    int Ans[N], dep[N], Sz[N], Fa[N];
     
    struct Link_list {
        int Head[N], Tot, Nxt[M << 1], to[M << 1];
        inline void AddEdgepair(int a, int b) {
            to[++Tot] = b, Nxt[Tot] = Head[a], Head[a] = Tot;
            to[++Tot] = a, Nxt[Tot] = Head[b], Head[b] = Tot;
        }
    } G;
     
    struct BIT {
        int C[N];
        inline void Add(int x, int y) {
            while (x < N)C[x] += y, x += x & -x;
        }
        inline int Sum(int x) {
            int res = 0;
            while (x)res += C[x], x -= x & -x;
            return res;
        }
    } tr;
     
    struct node {
        int b, id;
    };
     
    vector<node>Q[N];
     
    void dfs(int x, int pre) {
        dep[x] = dep[pre] + 1, Sz[x] = 1, Fa[x] = pre;
        ret(i, 0, Q[x].size()) {
            int ID = Q[x][i].id, b = Q[x][i].b;
            Ans[ID] -= tr.Sum(dep[x] + b) - tr.Sum(dep[x]);
        }
        erep(i, G, x) {
            int y = G.to[i];
            if (y == pre)continue;
            dfs(y, x);
            Sz[x] += Sz[y];
        }
        ret(i, 0, Q[x].size()) {
            int ID = Q[x][i].id, b = Q[x][i].b;
            Ans[ID] += min(dep[x] - 1, b) * (Sz[x] - 1);
            Ans[ID] += tr.Sum(dep[x] + b) - tr.Sum(dep[x]);
        }
        tr.Add(dep[x], Sz[x] - 1);
    }
     
    bool MOP2;
     
    inline void _main(void) {
        int n = Raed(), q = Read();
        ret(i, 1, n) {
            int a = Raed(), b = Raed();
            G.AddEdgepair(a, b);
        }
        rep(i, 1, q) {
            int a = Read(), b = Read();
            Q[a].push_back((node) {b, i});
        }
        dfs(1, 0);
        rep(i, 1, q)printf("%lld
    ", Ans[i]);
    }
     
    signed main() {
    #define offline1
    #ifdef offline
        freopen("tree.in", "r", stdin);
        freopen("tree.out", "w", stdout);
        _main();
        fclose(stdin); fclose(stdout);
    #else
        _main();
    #endif
        return 0;
    }
    
  • 相关阅读:
    同一内网不能网段ping 不通
    mysql 5.6.33 重置密码后报错
    设置tomcat内存设定
    python 取两数的百分比
    cache buffers
    登录到mysql查看binlog日志
    mysqlbinlog 查看日志时发生报错
    find 查找文件 -exec 然后压缩 查看tar包的内容
    zip 压缩文件 unzip查看zip压缩包内的内容
    react-native 完整实现登录功能
  • 原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11263272.html
Copyright © 2011-2022 走看看