3653: 谈笑风生
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 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
1 2
1 3
2 4
4 5
2 2
4 1
2 3
Sample Output
3
1
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 }