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 。
分析:
树上路径第K大带修改,实际上就是BZOJ 2588 + BZOJ 1901,用树状数组套主席树。
根据DFS序将节点放入树状数组,则每个节点及其子树都对应树状数组上的一段,把树状数组差分来看,一个节点对应的主席树版本就是它的前缀和主席树,每次修改子树,就是修改一段区间[l,r],而差分之后只要修改l和r+1就好了。
查询的时候,找四个主席树版本(树状数组上的前缀和),节点A、B,和节点A、B的LCA以及LCA的父亲,然后随便搞就好了。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 #define rint register int 6 7 int n, q, u, v, pow[100000]; 8 int k[100000], a[100000], b[100000]; 9 int begin[100000], end[100000]; 10 int fa[100000][22], depth[100000]; 11 12 char ch,B[1<<15],*S=B,*T=B,buf[1<<21],*O=buf,stk[40]; 13 #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++) 14 inline const int getint() //输入优化 15 { 16 char c = getc(); 17 rint k = 1, r = 0; 18 for(; c < ‘0‘ || c > ‘9‘; c = getc()) 19 if(c == ‘-‘) k = -1; 20 for(; c >= ‘0‘ && c <= ‘9‘; c = getc()) 21 r = r * 10 + c - ‘0‘; 22 return k * r; 23 } 24 25 int lca(rint x, rint y) //找LCA 26 { 27 rint i; 28 if (depth[x] < depth[y]) 29 x ^= y, y ^= x, x ^= y; 30 for (i = fa[x][21]; depth[x] > depth[y]; i--) 31 if (depth[fa[x][i]] >= depth[y]) x = fa[x][i]; 32 if (x == y) return x; 33 for (i = fa[x][21]; i >= 0; i--) 34 if (fa[x][i] != fa[y][i]) 35 x = fa[x][i], y = fa[y][i]; 36 return fa[x][0]; 37 38 } 39 40 /*********edges**********/ 41 int ep[200000], et[200000]; 42 int last[100000], en; 43 44 inline void addedge(rint f, rint t) //邻接表 45 { 46 en++; 47 ep[en] = last[f]; 48 last[f] = en; 49 et[en] = t; 50 } 51 52 /*****Discretization*****/ 53 int num[200000], count; 54 55 int lb(rint key) // lower_bound 56 { 57 rint l = 1, r = count, mid; 58 while (l < r) 59 { 60 mid = l + r >> 1; 61 if (num[mid] == key) 62 return mid; 63 if (num[mid] < key) 64 l = mid + 1; 65 else r = mid - 1; 66 } 67 return l; 68 } 69 70 void discretizate() //离散化 71 { 72 std::sort(num + 1, num + count + 1); 73 rint tmp = 0, i; 74 num[++count] = 1000000013; 75 for (i = 1; i <= count; i++) 76 { 77 if (num[i] != num[i + 1]) 78 num[++tmp] = num[i]; 79 } 80 count = tmp; 81 for (i = 1; i <= n; i++) 82 { 83 pow[i] = lb(pow[i]); 84 } 85 } 86 87 /********ZX-Tree*********/ 88 int nls[10000000], nrs[10000000], nsum[10000000]; 89 90 int ns, tmpos, tmdata; 91 92 void tmodify(int &t, rint left, rint right) //主席树上修改 93 { 94 if (t == 0) 95 { 96 nsum[t = ++ns] = 0; 97 } 98 if (left < right) 99 { 100 int mid = left + right >> 1; 101 if (tmpos <= mid) tmodify(nls[t], left, mid); 102 else tmodify(nrs[t], mid + 1, right); 103 nsum[t] += tmdata; 104 } else nsum[t] += tmdata; 105 } 106 107 /*******tree-array*******/ 108 int root[100000], rts; 109 110 void modify(rint x, rint y, rint pos, rint data) //树状数组上修改一段区间 111 { 112 tmpos = pos, tmdata = data; 113 for (; x <= n; x += x & -x) 114 tmodify(root[x], 1, count); 115 tmdata = -data; 116 for (y++; y <= n; y += y & -y) 117 tmodify(root[y], 1, count); 118 } 119 120 int rs[4][30]; 121 122 int init_rs(rint i, rint x) //用rs数组记录查询时需要用到的点 123 { 124 memset(rs[i], 0, sizeof (rs[i])); 125 int ret = 0; 126 for (; x > 0; x -= x & -x) 127 { 128 rs[i][++rs[i][0]] = root[x]; 129 ret += nsum[root[x]]; 130 } 131 return ret; 132 } 133 134 int query_rs() //查询每个点右儿子的大小 135 { 136 int ret = 0; rint i; 137 for (i = 1; i <= rs[0][0]; i++) 138 ret += nsum[nrs[rs[0][i]]]; 139 for (i = 1; i <= rs[1][0]; i++) 140 ret += nsum[nrs[rs[1][i]]]; 141 for (i = 1; i <= rs[2][0]; i++) 142 ret -= nsum[nrs[rs[2][i]]]; 143 for (i = 1; i <= rs[3][0]; i++) 144 ret -= nsum[nrs[rs[3][i]]]; 145 return ret; 146 } 147 148 void down(rint d) //将每个点变成它的左/右儿子 149 { 150 rint x, i; 151 for (x = 0; x < 4; x++) 152 for (i = 1; i <= rs[x][0]; i++) 153 rs[x][i] = d ? nrs[rs[x][i]] : nls[rs[x][i]]; 154 } 155 156 int query(rint x, rint y, rint data) //查询 157 { 158 int s = 0, f = lca(x, y), mid; 159 s += init_rs(0, begin[x]); 160 s += init_rs(1, begin[y]); 161 s -= init_rs(2, begin[f]); 162 s -= init_rs(3, begin[fa[f][0]]); 163 if (s < data) return -1; 164 int left = 1, right = count; 165 while (left < right) //迭代 166 { 167 mid = left + right >> 1; 168 s = query_rs(); 169 if (data > s) 170 { 171 down(0); 172 right = mid; 173 data -= s; 174 } 175 else 176 { 177 down(1); 178 left = mid + 1; 179 } 180 } 181 return num[left]; 182 } 183 184 /**********dfs***********/ 185 void DFS(rint x) //找出dfs序和求lca的rmq数组 186 { 187 rint i; 188 depth[x] = depth[fa[x][0]] + 1; 189 for (i = 0; fa[x][i]; fa[x][21] = ++i) 190 fa[x][i + 1] = fa[fa[x][i]][i]; 191 begin[x] = ++rts; 192 root[begin[x]] = ++ns; 193 for (i = last[x]; i; i = ep[i]) 194 if (begin[et[i]] == 0) 195 fa[et[i]][0] = x, DFS(et[i]); 196 end[x] = rts; 197 } 198 199 int main() 200 { 201 n = getint(); 202 q = getint(); 203 count = 0; 204 rint i, tmp; 205 for (i = 1; i <= n; i++) 206 num[++count] = pow[i] = getint(); 207 for (i = 1; i < n; i++) 208 { 209 u = getint(); 210 v = getint(); 211 addedge(u, v); 212 addedge(v, u); 213 } 214 for (i = 1; i <= q; i++) 215 { 216 k[i] = getint(); 217 a[i] = getint(); 218 b[i] = getint(); 219 if (k[i] == 0) num[++count] = b[i]; 220 } 221 discretizate(); 222 DFS(1); 223 for (i = 1; i <= n; i++) 224 { 225 modify(begin[i], end[i], pow[i], 1); 226 } 227 for (i = 1; i <= q; i++) 228 { 229 if (k[i]) 230 { 231 tmp = query(a[i], b[i], k[i]); 232 if (tmp >= 0) printf("%d\n", tmp); 233 else printf("invalid request!\n"); 234 } 235 else 236 { 237 modify(begin[a[i]], end[a[i]], pow[a[i]], -1); 238 pow[a[i]] = lb(b[i]); 239 modify(begin[a[i]], end[a[i]], pow[a[i]], 1); 240 } 241 } 242 }