1146: [CTSC2008]网络管理Network
Time Limit: 50 Sec Memory Limit: 162 MB
Submit: 3539 Solved: 1054
[Submit][Status][Discuss]
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大的路由器的延迟时间。注意N
,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。对于所有询问满足0<=K<=N
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
Source
本来以为是CDQ什么的,发现并不会;从DaD3zZ神犇那里看到带修主席树,表示也不会。
然后就是看代码学喽,各种RE各种WA,外加OJ上的TLE。直到代码长的都一模一样了才过,T_T,看来还有重新学习的必要。
DaD3zZ的题解,摘抄在下——
这道题方法很好想把,树上带修第k大问题,最直观的就是树链剖分+树套树,复杂度O(Nlog^4N),我是直接 dfs序+带修主席树 硬上,复杂度是O(Nlog^2N)
问题在于内存 ,所以可以考虑先建一棵完整的树,然后树状数组修改时只搞一条链这样能把内存大大降低。
并且,这里的dfs序直接用就好了,并不需要搞成入栈出栈序,那样内存消耗依旧很大,自己第一次大概是180M--MLE。
By DaD3zZ
另外记录一下带修主席树的大体思想:
一般主席树维护的是前缀关系,即 $Root_{i}$ 上含有从$1$到$i$的区间内的信息,而这样是不能修改的,因为改动区间中一个地方的信息,就需要把后面所有地方的 $Root_{j},i \leq j \leq n$ 全部修改。
带修主席树利用树状数组的形式,每个 $Root_{i}$ 上维护的只有树状数组上 $i$ 这个位置管辖的区间,这样更改区间中一处位置,只需要更改其在树状数组上的所有祖先节点,这是 $log_{2}N$ 级别的,所以总体复杂度是 $O(log_{2}^{2}N)$ 的。
而查询的时候,先开两个存放根节点的数组,分别为 $Add$ 和 $Sub$ ,代表需要加上$Add$中节点上的答案,减去$Sub$中节点上的答案。这个还好理解,原本主席树就是用 $Root_{i}$ 的答案减去 $Root_{j}$ 的答案从而得到 $(j,i]$ 这一区间的答案的,现在因为外层还有树状数组,所以 $i$ 和 $j$ 不唯一了,分别变为了一些结点。权值线段树上二分的时候还是类似,只是需要从多个 $Root$ 中计算出左(右)侧答案,进而判断应该向左还是右递归。注意递归的时候需要把所有 $Add$ 和 $Sub$ 中的结点向该方向递归。
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 5 inline int nextChar(void) 6 { 7 const static int siz = 1024; 8 9 static char buf[siz]; 10 static char *hd = buf + siz; 11 static char *tl = buf + siz; 12 13 if (hd == tl) 14 fread(hd = buf, 1, siz, stdin); 15 16 return *hd++; 17 } 18 19 inline int nextInt(void) 20 { 21 register int ret = 0; 22 register int neg = false; 23 register int bit = nextChar(); 24 25 for (; bit < 48; bit = nextChar()) 26 if (bit == ‘-‘)neg ^= true; 27 28 for (; bit > 47; bit = nextChar()) 29 ret = ret * 10 + bit - 48; 30 31 return neg ? -ret : ret; 32 } 33 34 const int siz = 80005; 35 36 int N, M; 37 38 int tim[siz]; 39 40 int map[siz << 1], tot; 41 42 int opt[siz], opx[siz], opy[siz]; 43 44 int edges; 45 int hd[siz]; 46 int to[siz << 1]; 47 int nt[siz << 1]; 48 49 inline void addEdge(int x, int y) 50 { 51 nt[edges] = hd[x]; to[edges] = y; hd[x] = edges++; 52 nt[edges] = hd[y]; to[edges] = x; hd[y] = edges++; 53 } 54 55 int dfn; 56 int arv[siz]; 57 int lev[siz]; 58 int dep[siz]; 59 int fa[siz][17]; 60 61 void preworkDFS(int u, int f) 62 { 63 arv[u] = ++dfn; 64 65 for (int i = 1; i <= 16; ++i) 66 fa[u][i] = fa[fa[u][i - 1]][i - 1]; 67 68 for (int i = hd[u], v; ~i; i = nt[i]) 69 if ((v = to[i]) != f) 70 { 71 fa[v][0] = u; 72 dep[v] = dep[u] + 1; 73 preworkDFS(v, u); 74 } 75 76 lev[u] = dfn + 1; 77 } 78 79 inline int lca(int a, int b) 80 { 81 if (dep[a] < dep[b]) 82 a ^= b ^= a ^= b; 83 84 for (int i = 16; i >= 0; --i) 85 if (dep[fa[a][i]] >= dep[b]) 86 a = fa[a][i]; 87 88 if (a == b)return a; 89 90 for (int i = 16; i >= 0; --i) 91 if (fa[a][i] != fa[b][i]) 92 a = fa[a][i], b = fa[b][i]; 93 94 return fa[a][0]; 95 } 96 97 int cnt; 98 int root[siz]; 99 int ls[siz * 80]; 100 int rs[siz * 80]; 101 int sm[siz * 80]; 102 103 std::vector<int> add; 104 std::vector<int> sub; 105 106 inline void clear(void) 107 { 108 add.clear(); 109 sub.clear(); 110 } 111 112 void insert(int l, int r, int &t, int f, int p, int v) 113 { 114 t = ++cnt; 115 116 ls[t] = ls[f]; 117 rs[t] = rs[f]; 118 119 sm[t] = sm[f] + v; 120 121 if (l != r) 122 { 123 int mid = (l + r) >> 1; 124 125 if (p <= mid) 126 rs[t] = rs[f], insert(l, mid, ls[t], ls[f], p, v); 127 else 128 ls[t] = ls[f], insert(mid + 1, r, rs[t], rs[f], p, v); 129 } 130 } 131 132 int query(int l, int r, int k) 133 { 134 if (l == r)return l; 135 136 int mid = (l + r) >> 1, sn = 0, sr = 0; 137 138 for (int i = 0; i < add.size(); ++i)sr += sm[rs[add[i]]], sn += sm[add[i]]; 139 for (int i = 0; i < sub.size(); ++i)sr -= sm[rs[sub[i]]], sn -= sm[sub[i]]; 140 141 if (sn < k) 142 return -1; 143 if (sr < k) 144 { 145 for (int i = 0; i < add.size(); ++i)add[i] = ls[add[i]]; 146 for (int i = 0; i < sub.size(); ++i)sub[i] = ls[sub[i]]; 147 148 return query(l, mid, k - sr); 149 } 150 else 151 { 152 for (int i = 0; i < add.size(); ++i)add[i] = rs[add[i]]; 153 for (int i = 0; i < sub.size(); ++i)sub[i] = rs[sub[i]]; 154 155 return query(mid + 1, r, k); 156 } 157 } 158 159 int bit[siz]; 160 161 inline void modify(int t, int p, int d) 162 { 163 for (int i = t; i <= dfn; i += i&-i) 164 insert(1, tot, bit[i], bit[i], p, d); 165 } 166 167 inline void addQuery(int t) 168 { 169 add.push_back(root[t]); 170 171 for (int i = arv[t]; i; i -= i&-i) 172 add.push_back(bit[i]); 173 } 174 175 inline void subQuery(int t) 176 { 177 sub.push_back(root[t]); 178 179 for (int i = arv[t]; i; i -= i&-i) 180 sub.push_back(bit[i]); 181 } 182 183 void buildDFS(int u, int f) 184 { 185 insert(1, tot, root[u], root[f], tim[u], 1); 186 187 for (int i = hd[u]; ~i; i = nt[i]) 188 if (to[i] != f)buildDFS(to[i], u); 189 } 190 191 signed main(void) 192 { 193 N = nextInt(); 194 M = nextInt(); 195 196 for (int i = 0; i <= N; ++i) 197 hd[i] = -1; 198 199 for (int i = 1; i <= N; ++i) 200 tim[i] = map[++tot] = nextInt(); 201 202 for (int i = 1; i < N; ++i) 203 addEdge(nextInt(), nextInt()); 204 205 for (int i = 1; i <= M; ++i) 206 { 207 opt[i] = nextInt(); 208 opx[i] = nextInt(); 209 opy[i] = nextInt(); 210 211 if (!opt[i]) 212 map[++tot] = opy[i]; 213 } 214 215 std::sort(map + 1, map + tot + 1); 216 217 tot = std::unique(map + 1, map + tot + 1) - map - 1; 218 219 for (int i = 1; i <= N; ++i) 220 tim[i] = std::lower_bound(map + 1, map + tot + 1, tim[i]) - map; 221 222 for (int i = 1; i <= M; ++i)if (!opt[i]) 223 opy[i] = std::lower_bound(map + 1, map + tot + 1, opy[i]) - map; 224 225 preworkDFS(1, 0); buildDFS(1, 0); 226 227 for (int i = 1; i <= M; ++i) 228 if (!opt[i]) 229 { 230 int x = opx[i]; 231 int y = opy[i]; 232 233 modify(arv[x], tim[x], -1); 234 modify(lev[x], tim[x], +1); 235 236 tim[x] = y; 237 238 modify(arv[x], tim[x], +1); 239 modify(lev[x], tim[x], -1); 240 } 241 else 242 { 243 clear(); 244 245 int x = opx[i]; 246 int y = opy[i]; 247 int t = lca(x, y); 248 249 addQuery(x); 250 addQuery(y); 251 subQuery(t); 252 subQuery(fa[t][0]); 253 254 int ans = query(1, tot, opt[i]); 255 256 if (ans == -1) 257 puts("invalid request!"); 258 else 259 printf("%d\n", map[ans]); 260 } 261 }
@Author: YouSiki