Contents
网络管理Network
题目
Description
M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门。为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络。该网络的结构由N个路由器和N-1条高速光缆组成。每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络。该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信。 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略。但是由于路由器老化,在这些路由器上进行数据交换会带来很大的延迟。而两个路由器之间的通信延迟时间则与这两个路由器通信路径上所有路由器中最大的交换延迟时间有关。作为M公司网络部门的一名实习员工,现在要求你编写一个简单的程序来监视公司的网络状况。该程序能够随时更新网络状况的变化信息(路由器数据交换延迟时间的变化),并且根据询问给出两个路由器通信路径上延迟第k大的路由器的延迟时间。
【任务】 你的程序从输入文件中读入N个路由器和N-1条光缆的连接信息,每个路由器初始的数据交换延迟时间Ti,以及Q条询问(或状态改变)的信息。并依次处理这Q条询问信息,它们可能是:
1. 由于更新了设备,或者设备出现新的故障,使得某个路由器的数据交换延迟时间发生了变化。
2. 查询某两个路由器a和b之间的路径上延迟第k大的路由器的延迟时间。
Input
第一行为两个整数N和Q,分别表示路由器总数和询问的总数。
第二行有N个整数,第i个数表示编号为i的路由器初始的数据延迟时间Ti。
紧接着N-1行,每行包含两个整数x和y。表示有一条光缆连接路由器x和路由器y。
紧接着是Q行,每行三个整数k、a、b。如果k=0,则表示路由器a的状态发生了变化,它的数据交换延迟时间由Ta变为b。如果k>0,则表示询问a到b的路径上所经过的所有路由器(包括a和b)中延迟第k大的路由器的延迟时间。注意a可以等于b,此时路径上只有一个路由器。
Output
对于每一个第二种询问(k>0),输出一行。包含一个整数为相应的延迟时间。
如果路径上的路由器不足k个,则输出信息“invalid request!”(全部小写不包含引号,两个单词之间有一个空格)。
Sample Input
5 5
5 1 2 3 4
3 1
2 1
4 3
5 3
2 4 5
0 1 2
2 2 3
2 1 4
3 3 5
Sample Output
3
2
2
invalid request!
Hint
10% 测试数据满足N<=8000,Q<=3000
40% 测试数据满足所有询问中1<=K<=5 。即路由器的延迟时间不会发生变化
100% 测试数据满足N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。对于所有询问满足0<=K<=N
Source
CTSC2008
题解
题意
求树上路径动态第K大
思路
第一种做法
比较直接,就是先树链剖分一下转化为区间问题,然后线段树套平衡树,最后二分答案
时间复杂度:
创建:\( O(nlg^2n)\)
查询:\( O(lg^4n)\)
修改:\( O(lg^2n)\)
空间复杂度:
创建:\( O(nlgn)\)
修改:\( O(1)\)
第二种做法
如果做过COT的话就会想到主席树,这题就是动态版的COT,所以需要动态版的主席树,就是树状数组套主席树,当然之前还要树剖一下
时间复杂度:
创建:\( O(nlgn)\)
查询:\( O(lg^3n)\)
修改:\( O(lg^2n)\)
空间复杂度:
创建:\( O(nlgn)\)
修改:\( O(k \times nlg^2n)\)(k为修改次数)
源码
第一种做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
/************************************************************************ * File Name : bzoj1146.cpp * Purpose : bzoj1146 : light-heavy-composition + SegmentTree + SplayTree + binary-search-answer * Creation Date : 2016年09月29日 * Last Modified : 2016年10月02日 星期日 15时47分35秒 * Created By : gou4shi1@qq.com ************************************************************************/ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define key_pos ch[ch[root][1]][0] const int MAXN = 80000 + 10; const int MAXM = 4000000 + 10; const int MIN = 0; const int MAX = 1E8 + 10; typedef int ARRAY[MAXN]; typedef int ARRAY2[MAXM]; ARRAY val, head, fa, depth, size, h_son, pos, arc_pos, top; int edge_size, pos_size, now; struct Edge { int to, next; } edge[MAXN << 1]; struct SegTree { int l, r; int root; inline int mid() { return (l+r) >> 1; } } tree[MAXN << 2]; struct SplayTree { int ch[MAXM][2]; ARRAY2 fa,sz,val; int node_size; void newNode(int &x, int y, int v) { x = ++node_size; sz[x] = 1; ch[x][0] = ch[x][1] = 0; fa[x] = y; val[x] = v; } void init(int &x) { newNode(x, 0, -1); newNode(ch[x][1], x, MAX); pushUp(ch[x][1]); pushUp(x); } void pushUp(int x) { if (!x) return; sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; } int sgn(int x) { return x == ch[fa[x]][1]; } void setCh(int y, int s, int x) { ch[y][s] = x; fa[x] = y; } void rotate(int x, int s) { int y = fa[x]; int z = fa[y]; setCh(y, !s, ch[x][s]); if (z) setCh(z, sgn(y), x); fa[x] = z; setCh(x, s, y); pushUp(y); } void splay(int x, int goal = 0) { if (!x) return; while (fa[x] != goal) { int y = fa[x]; int z = fa[y]; if (z == goal) { rotate(x, !sgn(x)); break; } else if (ch[z][0] == y) { ch[y][0] == x ? rotate(y, 1) : rotate(x, 0); rotate(x, 1); } else { ch[y][1] == x ? rotate(y, 0) : rotate(x, 1); rotate(x, 0); } } pushUp(x); if (!goal) tree[now].root = x; } int getKth(int x, int k) { while (x) { if (sz[ch[x][0]] + 1 == k) return x; else if (sz[ch[x][0]] + 1 > k) x = ch[x][0]; else { k -= sz[ch[x][0]] + 1; x = ch[x][1]; } } return x; } int getSE(int v) { int x = tree[now].root; int rank = 0; while (x) { if (val[x] <= v) { rank += sz[ch[x][0]] + 1; x = ch[x][1]; } else x = ch[x][0]; } return rank; } int getGE(int v) { int x = tree[now].root; int ans = 0; while (x) { if (val[x] >= v) { ans += sz[ch[x][1]] + 1; x = ch[x][0]; } else x = ch[x][1]; } return ans; } void ins(int v) { int k = getSE(v); splay(getKth(tree[now].root, k), 0); splay(getKth(tree[now].root, k+1), tree[now].root); int root = tree[now].root; newNode(key_pos, ch[root][1], v); pushUp(ch[root][1]); pushUp(root); } void del(int v) { int k = getSE(v); splay(getKth(tree[now].root, k-1), 0); splay(getKth(tree[now].root, k+1), tree[now].root); int root = tree[now].root; val[key_pos] = fa[key_pos] = 0; key_pos = 0; pushUp(ch[root][1]); pushUp(root); } } sp; void init() { memset(val, 0, sizeof(val)); memset(head, 0, sizeof(head)); memset(fa, 0, sizeof(fa)); memset(depth, 0, sizeof(depth)); memset(size, 0, sizeof(size)); memset(h_son, 0, sizeof(h_son)); edge_size = 0; pos_size = 0; now = 0; } inline void addEdge(int u, int v) { edge[++edge_size].to = v; edge[edge_size].next = head[u]; head[u] = edge_size; } void LHC_DFS1(int u) { size[u] = 1; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if (v == fa[u]) continue; fa[v] = u; depth[v] = depth[u] + 1; LHC_DFS1(v); size[u] += size[v]; if (size[v] > size[h_son[u]]) h_son[u] = v; } } void LHC_DFS2(int u, int u_top) { pos[u] = ++pos_size; arc_pos[pos[u]] = u; top[u] = u_top; if (!h_son[u]) return; LHC_DFS2(h_son[u], u_top); for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if (v == fa[u] || v == h_son[u]) continue; LHC_DFS2(v, v); } } void segTreeBuild(int rt, int l, int r) { tree[rt].l = l; tree[rt].r = r; sp.init(tree[rt].root); if (l == r) return; segTreeBuild(rt << 1, l, tree[rt].mid()); segTreeBuild(rt<<1 | 1, tree[rt].mid()+1, r); } void segTreeModify(int pos, int old, int new_val, int rt) { now = rt; if (old != -1) sp.del(old); sp.ins(new_val); if (tree[rt].l == tree[rt].r) return; if (pos <= tree[rt].mid()) segTreeModify(pos, old, new_val, rt << 1); else segTreeModify(pos, old, new_val, rt<<1 | 1); } int segTreeQueryGE(int l, int r, int v, int rt) { now = rt; if (l <= tree[rt].l && tree[rt].r <= r) return sp.getGE(v) - 1; if (r <= tree[rt].mid()) return segTreeQueryGE(l, r, v, rt << 1); if (l > tree[rt].mid()) return segTreeQueryGE(l, r, v, rt<<1 | 1); return segTreeQueryGE(l, r, v, rt << 1) + segTreeQueryGE(l, r, v, rt<<1 | 1); } int askGE(int a, int b, int v) { int ans = 0; while (top[a] != top[b]) { if (depth[top[a]] < depth[top[b]]) swap(a,b); ans += segTreeQueryGE(pos[top[a]], pos[a], v, 1); a = fa[top[a]]; } if (depth[a] > depth[b]) swap(a,b); ans += segTreeQueryGE(pos[a], pos[b], v, 1); return ans; } int binAns(int a, int b, int k) { int ans = -1; int l = MIN, r = MAX; while (l <= r) { int mid = (l+r) >> 1; int ge = askGE(a, b, mid); if (ge >= k) { ans = mid; l = mid + 1; } else r = mid - 1; } return ans; } int main() { int n, q; while (~scanf("%d%d", &n, &q)) { init(); for (int i = 1; i <= n; ++i) scanf("%d", &val[i]); for (int i = 1; i <= n-1; ++i) { int u, v; scanf("%d%d", &u, &v); addEdge(u,v); addEdge(v,u); } LHC_DFS1(1); LHC_DFS2(1, 1); segTreeBuild(1, 1, n); for (int i = 1; i <= n; ++i) segTreeModify(pos[i], -1, val[i], 1); while (q--) { int k, a, b; scanf("%d%d%d", &k, &a, &b); if (!k) { segTreeModify(pos[a], val[a], b, 1); val[a] = b; continue; } else { int ans = binAns(a, b, k); if (~ans) printf("%d\n", ans); else puts("invalid request!"); } } } return 0; } |
第二种做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
/************************************************************************ * File Name : bzoj1146_2.cpp * Purpose : bzoj1146 : light-heavy-composition + binaryIndexedTree + chairmenTree * Creation Date : 2016年10月01日 * Last Modified : 2016年10月02日 星期日 15时47分30秒 * Created By : gou4shi1@qq.com 6***********************************************************************/ #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> using namespace std; const int MAXN = 80000 + 10; typedef int ARRAY[MAXN]; typedef int ARRAY2[MAXN << 1]; ARRAY val, num, head, fa, depth, size, h_son, pos, arc_pos, top; ARRAY2 HASH, root, L, R; int edge_size, pos_size, node_size, num_size, L_size, R_size, seg_size, n; struct Edge { int to, next; } edge[MAXN << 1]; inline void addEdge(int u, int v) { edge[++edge_size].to = v; edge[edge_size].next = head[u]; head[u] = edge_size; } inline int read() { char c = getchar(); for (; !isdigit(c); c = getchar()); int ret = 0; for (; isdigit(c); c = getchar()) ret = ret * 10 + c - '0'; return ret; } struct Query { int k, a, b; void init() { k = read(); a = read(); b = read(); } } q[MAXN]; struct ChairTreeNode { int s, l , r; } tree[MAXN * 100]; void newNode(int &x, int sum, int L, int R) { x = ++node_size; tree[x].s = sum; tree[x].l = L; tree[x].r = R; } void init() { memset(head, 0, sizeof(head)); memset(h_son, 0, sizeof(h_son)); fa[1] = 0; depth[1] = 0; size[0] = 0; memset(root, 0, sizeof(root)); tree[0].s = tree[0].l = tree[0].r = 0; edge_size = 0; pos_size = 0; node_size = 0; num_size = 0; } void LHC_DFS1(int u) { size[u] = 1; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if (v == fa[u]) continue; fa[v] = u; depth[v] = depth[u] + 1; LHC_DFS1(v); size[u] += size[v]; if (size[v] > size[h_son[u]]) h_son[u] = v; } } void LHC_DFS2(int u, int u_top) { pos[u] = ++pos_size; arc_pos[pos[u]] = u; top[u] = u_top; if (!h_son[u]) return; LHC_DFS2(h_son[u], u_top); for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if (v == fa[u] || v == h_son[u]) continue; LHC_DFS2(v, v); } } void chairTreeBuild(int &rt, int pre_rt, int pos, int l, int r) { newNode(rt, tree[pre_rt].s + 1, tree[pre_rt].l, tree[pre_rt].r); if (l == r) return; int m = (l + r) >> 1; if (pos <= m) chairTreeBuild(tree[rt].l, tree[pre_rt].l, pos, l, m); else chairTreeBuild(tree[rt].r, tree[pre_rt].r, pos, m+1, r); } void chairTreeModify(int &rt, int val, int pos, int l, int r) { if (!rt) newNode(rt, 0, 0, 0); tree[rt].s += val; if (l == r) return; int m = (l+r) >> 1; if (pos <= m) chairTreeModify(tree[rt].l, val, pos, l, m); else chairTreeModify(tree[rt].r, val, pos, m+1, r); } int chairTreeQueryKth(int l, int r, int k) { if (l == r) return l; int m = (l+r) >> 1, cnt = 0; for (int i = 0; i != R_size; ++i) cnt += tree[tree[R[i]].l].s; for (int i = 0; i != L_size; ++i) cnt -= tree[tree[L[i]].l].s; if (k <= cnt) { for (int i = 0; i != R_size; ++i) R[i] = tree[R[i]].l; for (int i = 0; i != L_size; ++i) L[i] = tree[L[i]].l; return chairTreeQueryKth(l, m, k); } else { for (int i = 0; i != R_size; ++i) R[i] = tree[R[i]].r; for (int i = 0; i != L_size; ++i) L[i] = tree[L[i]].r; return chairTreeQueryKth(m+1, r, k-cnt); } } inline int lowBit(int x) { return x & (-x); } void BIT_query(int l, int r) { seg_size += r - l + 1; R[R_size++] = root[r+n]; for (int rr = r; rr; rr -= lowBit(rr)) R[R_size++] = root[rr]; L[L_size++] = root[l-1 == 0 ? 0 : l-1 + n]; for (int ll = l-1; ll; ll -= lowBit(ll)) L[L_size++] = root[ll]; } void BIT_modify(int pos, int sgn, int val) { for (int i = pos; i <= n; i += lowBit(i)) chairTreeModify(root[i], sgn, val, 1, num_size); } int ask(int a, int b, int k) { L_size = R_size = seg_size = 0; for (; top[a] != top[b]; a = fa[top[a]]) { if (depth[top[a]] < depth[top[b]]) swap(a, b); BIT_query(pos[top[a]], pos[a]); } if (depth[a] > depth[b]) swap(a, b); BIT_query(pos[a], pos[b]); if (seg_size < k) return -1; return HASH[chairTreeQueryKth(1, num_size, seg_size-k+1)]; } int main() { int Q; while (~scanf("%d%d", &n, &Q)) { init(); for (int i = 1; i <= n; ++i) { val[i] = read(); HASH[++num_size] = val[i]; } for (int i = 1; i <= n-1; ++i) { int u = read(), v = read(); addEdge(u,v); addEdge(v,u); } for (int i = 1; i <= Q; ++i) { q[i].init(); if (!q[i].k) HASH[++num_size] = q[i].b; } --num_size; sort(HASH+1, HASH+1 + num_size); num_size = unique(HASH+1, HASH+1 + num_size) - (HASH+1); for (int i = 1; i <= n; ++i) num[i] = lower_bound(HASH+1, HASH+1 + num_size, val[i]) - HASH; LHC_DFS1(1); LHC_DFS2(1, 1); for (int i = 1; i <= n; ++i) chairTreeBuild(root[i+n], root[i+n - 1], num[arc_pos[i]], 1, num_size); for (int i = 1; i <= Q; ++i) { if (!q[i].k) { BIT_modify(pos[q[i].a], -1, num[q[i].a]); num[q[i].a] = lower_bound(HASH+1, HASH+1+num_size, q[i].b) - HASH; BIT_modify(pos[q[i].a], 1, num[q[i].a]); } else { int ans = ask(q[i].a, q[i].b, q[i].k); if (~ans) printf("%d\n", ans); else puts("invalid request!"); } } } return 0; } |
对拍
既然两种做法都打了一遍,赶紧对拍一波
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/************************************************************************ * File Name : bzoj1146_dataMaker.cpp * Purpose : dataMaker of bzoj1146 * Creation Date : 2016年10月02日 * Last Modified : 2016年10月02日 星期日 15时47分39秒 * Created By : gou4shi1@qq.com ************************************************************************/ #include <cstdio> #include <cstdlib> #include <ctime> const int MAXN = 80000; const int MAXM = 1E8; inline void randomize() { srand(time(0)); } inline int random(int l, int r) { return l + rand()%(r-l+1); } int main() { randomize(); int n = random(1, MAXN), q = random(1, MAXN); printf("%d %d\n", n, q); for (int i = 1; i <= n-1; ++i) printf("%d ", random(1, MAXM)); printf("%d\n", random(1, MAXM)); for (int i = 2; i <= n; ++i) printf("%d %d\n", random(1, i-1), i); while (q--) { int type = random(0, 5); if (!type) printf("0 %d %d\n", random(1, n), random(1, MAXM)); else printf("%d %d %d\n", random(1, n<100 ? n : 100), random(1, n), random(1, n)); } return 0; } |
1 2 3 4 5 6 7 8 9 10 11 |
#!/bin/bash cnt=0 while true; do ./$1_dataMaker > $1.in ./$1 < $1.in > $1.out ./$1_2 < $1.in > $1_2.out diff $1.out $1_2.out let "cnt+=1" echo $cnt if [ $? -ne 0 ] ; then break; fi done |