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\n", dep[p]+1);
110 //        printf("dep_en : %d \n", 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\n", ret);
113     }
114     return 0;
115 }
View Code

 

posted @ 2017-03-21 16:06  Splay  阅读(251)  评论(0编辑  收藏  举报