zoukankan      html  css  js  c++  java
  • BZOJ 3653 谈笑风生 dfs序 可持久化线段树

    3653: 谈笑风生

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 628  Solved: 245
    [Submit][Status][Discuss]

    Description

    设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。

    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

    HINT

    1<=P<=N
    1<=K<=N
    N<=300000
    Q<=300000

    Source

    Solution

    对于一组询问(p,k),其答案为min(k, dep[p]-1)*(siz[p]-1)+∑(siz[v]-1)(v∈p的子树)

    前面的东西可以直接求,后面的东西考虑在dfs序上建一棵线段树,然后根据深度把点扔进去,可持久化。

    Code

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
      6 #define REP_EDGE(i, a) for (int i = (a); i != -1; i = e[i].nxt)
      7 #define mset(a, b) memset(a, b, sizeof(a))
      8 const int maxn = 3e5+10;
      9 int n, q;
     10 struct Edge
     11 {
     12     int v, nxt;
     13     Edge (int v = 0, int nxt = 0): v(v), nxt(nxt) {}
     14 }e[maxn*2];
     15 int head[maxn], label;
     16 int siz[maxn], dfn[maxn], to[maxn], dep[maxn], dfn_clock;
     17 struct Node
     18 {
     19     int u, u_dep, u_siz;
     20     Node (int u = 0, int u_dep = 0, int u_siz = 0): u(u), u_dep(u_dep), u_siz(u_siz) {}
     21     bool operator < (const Node &AI) const { return u_dep < AI.u_dep; }
     22 }d[maxn];
     23 
     24 void ins(int u, int v)
     25 {
     26     e[++label] = Edge(v, head[u]), head[u] = label;
     27     e[++label] = Edge(u, head[v]), head[v] = label;
     28 }
     29 
     30 void dfs(int u, int fa)
     31 {
     32     dep[u] = dep[fa]+1, siz[u] = 1, dfn[u] = ++dfn_clock, to[dfn_clock] = u;
     33     REP_EDGE(i, head[u])
     34     {
     35         int v = e[i].v;
     36         if (v == fa) continue ;
     37         dfs(v, u), siz[u] += siz[v];
     38     }
     39 }
     40 
     41 struct Tree
     42 {
     43     int ls[maxn*50], rs[maxn*50], sum[maxn*50], t_cnt;
     44     Tree() { t_cnt = 0; }
     45     void pushup(int rt)
     46     {
     47         sum[rt] = sum[ls[rt]]+sum[rs[rt]];
     48     }
     49     void insert(int rt, int las_rt, int l, int r, int p, int d)
     50     {
     51         if (l == r)
     52         {
     53             sum[rt] = d;
     54             return ;
     55         }
     56         int mid = (l+r)>>1;
     57         if (p <= mid)
     58         {
     59             ls[rt] = ++t_cnt, rs[rt] = rs[las_rt];
     60             insert(ls[rt], ls[las_rt], l, mid, p, d);
     61         }
     62         else
     63         {
     64             ls[rt] = ls[las_rt], rs[rt] = ++t_cnt;
     65             insert(rs[rt], rs[las_rt], mid+1, r, p, d);
     66         }
     67         pushup(rt);
     68     }
     69     int query(int rt_1, int rt_2, int l, int r, int L, int R)
     70     {
     71         if (L <= l && r <= R)
     72             return sum[rt_2]-sum[rt_1];
     73         int mid = (l+r)>>1, ret = 0;
     74         if (L <= mid) ret = query(ls[rt_1], ls[rt_2], l, mid, L, R);
     75         if (R > mid) ret += query(rs[rt_1], rs[rt_2], mid+1, r, L, R);
     76         return ret;
     77     }
     78 }T;
     79 int rt[maxn], st_p[maxn];
     80 
     81 int main()
     82 {
     83     scanf("%d %d", &n, &q);
     84     REP(i, 1, n) head[i] = -1;
     85     label = -1;
     86     REP(i, 1, n-1)
     87     {
     88         int u, v;
     89         scanf("%d %d", &u, &v);
     90         ins(u, v);
     91     }
     92     dfn_clock = 0, dfs(1, 0);
     93     REP(i, 1, n) d[i] = Node(i, dep[i], siz[i]);
     94     sort(d+1, d+n+1);
     95     rt[0] = 0;
     96     REP(i, 1, n)
     97     {
     98         rt[i] = ++T.t_cnt;
     99         T.insert(rt[i], rt[i-1], 1, n, dfn[d[i].u], d[i].u_siz-1);
    100         if (d[i].u_dep != d[i-1].u_dep) st_p[d[i].u_dep] = i;
    101     }
    102     int max_dep = d[n].u_dep;
    103     st_p[max_dep+1] = n+1;
    104     while (q --)
    105     {
    106         int p, k;
    107         scanf("%d %d", &p, &k);
    108         int ret = min(dep[p]-1, k)*(siz[p]-1);
    109 //        printf("dep_st : %d
    ", dep[p]+1);
    110 //        printf("dep_en : %d 
    ", min(max_dep, dep[p]+k)+1);
    111         ret += T.query(rt[st_p[dep[p]+1]-1], rt[st_p[min(max_dep, dep[p]+k)+1]-1], 1, n, dfn[p], dfn[p]+siz[p]-1);
    112         printf("%d
    ", ret);
    113     }
    114     return 0;
    115 }
    View Code
  • 相关阅读:
    linux的ls命令输出结果的逐条解释
    dubbo用途介绍
    dubbo有什么作用
    来自19岁女孩和软件开发人员的建议
    C++的反思[转]
    mysql各种引擎对比、实战
    俗话:MySQL索引
    Mysql 30条军规
    MySQL事务原理&实战【官方精译】
    php-msf 源码解读【转】
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6594865.html
Copyright © 2011-2022 走看看