洛谷 P4216 [SCOI2015]情报传递
题目描述
奈特公司是一个巨大的情报公司,它有着庞大的情报网络。情报网络中共有 nn 名情报员。每名情报员可能有若干名 (可能没有) 下线,除 11 名大头目外其余 n-1n−1 名情报员有且仅有 11 名上线。奈特公司纪律森严,每名情报员只能与自己的上、下线联系,同时,情报网络中任意两名情报员一定能够通过情报网络传递情报。
奈特公司每天会派发以下两种任务中的一个任务:
- 搜集情报:指派 TT 号情报员搜集情报;
- 传递情报:将一条情报从 XX 号情报员传递给 YY 号情报员。
情报员最初处于潜伏阶段,他们是相对安全的,我们认为此时所有情报员的危险值为 00;一旦某个情报员开始搜集情报,他的危险值就会持续增加,每天增加 11 点危险值 (开始搜集情报的当天危险值仍为 00,第 22天危险值为 11,第 33 天危险值为 22,以此类推)。传递情报并不会使情报员的危险值增加。
为了保证传递情报的过程相对安全,每条情报都有一个风险控制值 CC。奈特公司认为,参与传递这条情报的所有情报员中,危险值大于 CC 的情报员将对该条情报构成威胁。现在,奈特公司希望知道,对于每个传递情报任务,参与传递的情报员有多少个,其中对该条情报构成威胁的情报员有多少个。
输入格式
第一行包含一个正整数 nn,表示情报员个数。 笫二行包含 nn 个非负整数,其中第 ii 个整数 P_iPi 表示 ii 号情报员上线的编号。特别地,若 P_i=0Pi=0,表示 ii 号情报员是大头目。 第三行包含一个正整数 qq,表示奈特公司将派发 qq 个任务 (每天一个)。
随后 qq 行,依次描述 qq 个任务。每行首先有一个正整数 kk。
- 若 k=1k=1,表示任务是传递情报,随后有三个正整数 X_iXi、Y_iYi、C_iCi,依次表示传递情报的起点、终点和风险控制值。
- 若 k=2k=2,表示任务是搜集情报,随后有 11 个正整数 T_iTi,表示搜集情报的情报员编号。
输出格式
对于每个传递情报任务输出一行,包含两个整数,分别是参与传递情报的情报员个数和对该条情报构成威胁的情报员个数。
输入输出样例
7 0 1 1 2 2 3 3 6 1 4 7 0 2 1 2 4 2 7 1 4 7 1 1 4 7 3
5 0 5 2 5 1
说明/提示
样例解释:
对于 3 个传递情报任务,都是经过 5 名情报员,分别是 4 号、2 号、1 号、3 号和 7 号。
- 第 1 个任务,所有情报员 (危险值为 0) 都不对情报构成威胁;
- 第 2 个任务,有 2 名情报员对情报构成威胁,分别是 1 号情报员 (危险值为 3) 和 4 号情报员 (危险值为 2),7 号情报员 (危险值为 1) 并不构成威胁;
- 第 3 个任务,只有 1 名情报员对情报构成威胁。
数据范围:
n\leqslant 2\times 10^5,Q\leqslant 2\times 10^5,0<P_i,C_i\leqslant N,1\leqslant T_i,X_i,Y_i\leqslant nn⩽2×105,Q⩽2×105,0<Pi,Ci⩽N,1⩽Ti,Xi,Yi⩽n。
思路:不得不说这也是道好题,我们从题目中可以看出来,每次查询是求一段值域,所以我们可以用可持久化值域线段树(即主席树)去解决查询问题,那么我们再来看看其他细节,其中有一个是:危险值一开始为0,而后每天都会增加,这想到了什么?带修改的主席树?肯定不行,因为时间复杂度太大了这样做,我们肯定要想一个更加讨巧的方法去解决这个问题。我这里用了一个方法,离线处理,对于所有的询问(即编号为1的操作),我们先存下来,而赋值操作(即编号为2的操作),我们用一个“相对运动”的方法,“假定”所有赋值操作、询问操作都是在最后一天完成的,这样每一个赋值操作就有了明确的值,与天数有关。同样的,由于相对性,询问操作的“风险控制值”也同样应该加上相同的数才能保持“相对静止”。
同时,由于本题的特殊性,这样“相对运动”操作并不会对正确答案造成任何影响。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 inline int read() 8 { 9 int ret = 0; 10 char ch = getchar(); 11 while(ch < '0' || ch > '9') ch = getchar(); 12 while(ch >= '0' && ch <= '9') 13 {ret = ret * 10 + ch - '0'; ch = getchar();} 14 return ret; 15 } 16 const int N = 2e5 + 10; 17 struct edge{ 18 int to, nxt; 19 }e[N << 1]; 20 int head[N], tot = 0; 21 void adde(int f, int t) 22 { 23 e[++ tot] = (edge){t, head[f]}; 24 head[f] = tot; 25 } 26 int deep[N], fa[N], siz[N], hson[N]; 27 void dfs1(int u, int f) 28 { 29 deep[u] = deep[f] + 1; 30 fa[u] = f; 31 siz[u] = 1; 32 for(int i = head[u]; i; i = e[i].nxt) 33 { 34 int v = e[i].to; 35 if(v == f) continue; 36 dfs1(v, u); 37 siz[u] += siz[v]; 38 if(!hson[u] || siz[v] > siz[hson[u]]) hson[u] = v; 39 } 40 } 41 int top[N], inseg[N], intr[N], segcnt = 0; 42 void dfs2(int u, int tp) 43 { 44 top[u] = tp; 45 inseg[u] = ++ segcnt; 46 intr[segcnt] = u; 47 if(!hson[u]) return; 48 dfs2(hson[u], tp); 49 for(int i = head[u]; i; i = e[i].nxt) 50 { 51 int v = e[i].to; 52 if(v == fa[u] || v == hson[u]) continue; 53 dfs2(v, v); 54 } 55 } 56 int ls[N << 5], rs[N << 5], s[N << 5]; 57 int rt[N], nodecnt = 0; 58 void build(int &p, int l, int r) 59 { 60 p = ++ nodecnt; 61 if(l == r) return; 62 int mid = l + r >> 1; 63 build(ls[p], l, mid); 64 build(rs[p], mid + 1, r); 65 } 66 int modify(int pre, int l, int r, int pos) 67 { 68 int p = ++ nodecnt; 69 ls[p] = ls[pre]; 70 rs[p] = rs[pre]; 71 s[p] = s[pre] + 1; 72 if(l == r) return p; 73 int mid = l + r >> 1; 74 if(pos <= mid) ls[p] = modify(ls[p], l, mid, pos); 75 else rs[p] = modify(rs[p], mid + 1, r, pos); 76 return p; 77 } 78 int ask_cnt(int u, int v, int l, int r, int L, int R) 79 { 80 if(L <= l && R >= r) return s[v] - s[u]; 81 int mid = l + r >> 1; 82 int ret = 0; 83 if(L <= mid) ret += ask_cnt(ls[u], ls[v], l, mid, L, R); 84 if(R > mid) ret += ask_cnt(rs[u], rs[v], mid + 1, r, L, R); 85 return ret; 86 } 87 int n, m; 88 int lca(int x, int y) 89 { 90 int fx = top[x], fy = top[y]; 91 while(fx != fy) 92 { 93 if(deep[fx] < deep[fy]) swap(x, y), swap(fx, fy); 94 x = fa[fx], fx = top[x]; 95 } 96 if(deep[x] < deep[y]) swap(x, y); 97 return y; 98 } 99 int find_cnt(int x, int y, int d) 100 { 101 int fx = top[x], fy = top[y]; 102 int ret = 0; 103 while(fx != fy) 104 { 105 if(deep[fx] < deep[fy]) swap(x, y), swap(fx, fy); 106 ret += ask_cnt(rt[inseg[fx] - 1], rt[inseg[x]], 1, m + 2, d + 1, m + 2); 107 x = fa[fx], fx = top[x]; 108 } 109 if(deep[x] < deep[y]) swap(x, y); 110 ret += ask_cnt(rt[inseg[y] - 1], rt[inseg[x]], 1, m + 2, d + 1, m + 2); 111 return ret; 112 } 113 int num[N]; 114 struct node{ 115 int x, y, d; 116 }Q; 117 queue <node>que; 118 int main() 119 { 120 n = read(); 121 int a, b, c, d; 122 for(int i = 1; i <= n; i ++) 123 { 124 a = read(); 125 if(a == 0) b = i; 126 else 127 { 128 adde(i, a); 129 adde(a, i); 130 } 131 } 132 dfs1(b, 0); 133 dfs2(b, b); 134 m = read(); 135 for(int i = 1; i <= m; i ++) 136 { 137 a = read(), b = read(); 138 if(a == 1) 139 { 140 c = read(), d = read(); 141 que.push((node){b, c, max(1, min(m, d + m - i))}); 142 } 143 else num[b] = max(1, m - i); 144 } 145 build(rt[0], 1, m + 2); 146 for(int i = 1; i <= segcnt; i ++) 147 { 148 rt[i] = modify(rt[i - 1], 1, m + 2, num[intr[i]]); 149 } 150 while(!que.empty()) 151 { 152 Q = que.front(); 153 printf("%d ", 1 + deep[Q.x] + deep[Q.y] - 2 * deep[lca(Q.x, Q.y)]); 154 printf("%d\n", find_cnt(Q.x, Q.y, Q.d)); 155 que.pop(); 156 } 157 return 0; 158 }