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 55 1 2 3 43 12 14 35 32 4 50 1 22 2 32 1 43 3 5
Sample Output
322invalid request!
Hint
任意一个路由器在任何时刻都满足延迟时间小于10^8。对于所有询问满足0<=K<=N 。
Source
CTSC2008
【分析】
居然1A了,天不负有心人啊.....写了1个半小时TAT
裸的树上带修改第k大,用树链剖分转成线段树,在每个线段树里面维护一个平衡树。
查找的时候先二分答案,再按照树链剖分的方式找就行了。
发现动态内存分配还是蛮好的,均摊分析,空间复杂度不会爆。
1 /* 2 唐代韦庄 3 《菩萨蛮·劝君今夜须沈醉》 4 劝君今夜须沉醉,尊前莫话明朝事。珍重主人心,酒深情亦深。 5 须愁春漏短,莫诉金杯满。遇酒且呵呵,人生能几何! 6 */ 7 #include <iostream> 8 #include <cstdio> 9 #include <algorithm> 10 #include <cstring> 11 #include <vector> 12 #include <utility> 13 #include <iomanip> 14 #include <string> 15 #include <cmath> 16 #include <queue> 17 #include <assert.h> 18 #include <map> 19 #include <ctime> 20 #include <cstdlib> 21 #include <stack> 22 #include <set> 23 #define LOCAL 24 const int INF = 0x7fffffff; 25 const int MAXN = 80000 + 10; 26 const int maxnode = 20000 * 2 + 200000 * 20; 27 const int MAXM = 1000000 + 10; 28 const int MAX = 100000000; 29 using namespace std; 30 struct Treap{ 31 int val; 32 int fix, siz; 33 Treap *ch[2]; 34 35 void update(){ 36 siz = 1; 37 if (ch[0] != NULL) siz += ch[0]->siz; 38 if (ch[1] != NULL) siz += ch[1]->siz; 39 } 40 }; 41 //将t的d儿子换到t 42 void rotate(Treap *&t, int d){ 43 Treap *p = t->ch[d]; 44 t->ch[d] = p->ch[d ^ 1]; 45 t->update(); 46 p->ch[d ^ 1] = t; 47 p->update(); 48 t = p; 49 return; 50 } 51 Treap *NEW(int val){ 52 Treap *t = new Treap; 53 t->fix = rand(); 54 t->val = val; 55 t->siz = 1; 56 t->ch[0] = t->ch[1] = NULL; 57 return t; 58 } 59 void insert(Treap *&t, int val){ 60 if (t == NULL){ 61 t = NEW(val); 62 return; 63 } 64 int d = (val >= t->val); 65 insert(t->ch[d], val); 66 if (t->ch[d]->fix > t->fix) rotate(t, d); 67 t->update(); 68 } 69 int size(Treap *&t) {return (t == NULL) ? 0: t->siz;} 70 //统计比val大的数量,包括val! 71 int get(Treap *&t, int val){ 72 if (t == NULL) return 0; 73 //右边都比他大.. 74 if (val <= t->val) return size(t->ch[1]) + 1 + get(t->ch[0], val); 75 else return get(t->ch[1], val); 76 } 77 void erase(Treap *&t, int x){ 78 int d; 79 if (x == t->val) d = -1; 80 else d = (x > t->val);//随意删除一个就行了 81 82 if (d == -1){ 83 Treap *tmp = t; 84 if (t->ch[0] == NULL){//左儿子为0那么就变成右儿子 85 t = t->ch[1]; 86 delete tmp; 87 }else if (t->ch[1] == NULL){ 88 t = t->ch[0]; 89 delete tmp; 90 }else{//还没到叶子转下去 91 int f = (t->ch[1]->fix > t->ch[0]->fix); 92 rotate(t, f); 93 erase(t->ch[f ^ 1], x);//注意转到另一边了 94 } 95 }else erase(t->ch[d], x); 96 if (t != NULL) t->update(); 97 } 98 99 //------------------------以上为Treap------------------// 100 101 struct Node{//线段树的节点 102 int l, r; 103 Treap *t;//注意这个里面用动态内存分配...无奈. 104 Node *ch[2]; 105 }*root, mem[MAXN * 2]; 106 int n, q;//点数和询问总述数量 107 int head[MAXN * 2], to[MAXN * 2];//vector会爆? 108 int M, next[MAXN * 2], fa[MAXN]; 109 int Time, data[MAXN], son[MAXN], siz[MAXN], pos[MAXN];//时间轴 110 int top[MAXN], tot, dep[MAXN]; 111 112 void addEdge(int u, int v){ 113 to[M] = v; 114 next[M]= head[u]; 115 head[u] = M++; 116 } 117 void dfs_1(int u){ 118 son[u] = 0; 119 siz[u] = 1; 120 for (int i = head[u];i != -1; i = next[i]){ 121 int v = to[i]; 122 if (v == fa[u]) continue; 123 fa[v] = u; 124 dep[v] = dep[u] + 1; 125 dfs_1(v); 126 siz[u] += siz[v]; 127 if (siz[v] > siz[son[u]]) son[u] = v; 128 } 129 } 130 void dfs_2(int u, int top_node){ 131 pos[u] = ++Time; 132 top[u] = top_node; 133 if (son[u]) dfs_2(son[u], top_node); 134 for (int i = head[u]; i != -1; i = next[i]){ 135 int v = to[i]; 136 if (v == fa[u] || v == son[u]) continue; 137 dfs_2(v, v); 138 } 139 } 140 Node *NEW(int l, int r){ 141 Node *p = &mem[tot++]; 142 p->l = l; 143 p->r = r; 144 p->t = NULL;//p里面的treap 145 p->ch[0] = p->ch[1] = NULL; 146 return p; 147 } 148 void build(Node *&t, int l, int r){ 149 if (t == NULL){ 150 t = NEW(l, r); 151 } 152 if (l == r) return; 153 int mid = (l + r) >> 1; 154 build(t->ch[0], l, mid); 155 build(t->ch[1], mid + 1, r); 156 } 157 //居然是单点修改OAO 158 //将l位置的路由器延迟时间由x变为y 159 void change(Node *&p, int l, int x, int y){ 160 if (p->l == l && p->r == l){ 161 if (x != INF) erase(p->t, x);//为INF的时候就是单纯的插入 162 insert(p->t, y); 163 return; 164 } 165 if (x != INF) erase(p->t, x); 166 insert(p->t, y); 167 168 int mid = (p->l + p->r) >> 1; 169 if (l <= mid) change(p->ch[0], l, x, y); 170 else change(p->ch[1], l, x, y); 171 } 172 //表示在l,r这一段内比val大的数的个数 173 int query(Node *&p, int l, int r, int val){ 174 if (l <= p->l && p->r <= r) return get(p->t, val); 175 int mid = (p->l + p->r) >> 1; 176 int sum = 0; 177 if (l <= mid) sum += query(p->ch[0], l, r, val); 178 if (r > mid) sum += query(p->ch[1], l, r, val); 179 return sum; 180 } 181 void init(){ 182 memset(head, -1, sizeof(head)); 183 memset(dep, 0, sizeof(dep));//表示根到自己不包含根的节点数量 184 siz[0] = fa[1] = 0; 185 M = Time = 0; 186 187 scanf("%d%d", &n, &q); 188 for (int i = 1; i <= n; i++) scanf("%d", &data[i]); 189 for (int i = 1; i < n; i++){ 190 int u, v; 191 scanf("%d%d", &u, &v); 192 addEdge(u, v); 193 addEdge(v, u); 194 } 195 dfs_1(1); 196 dfs_2(1, 1); 197 build(root, 1, Time); 198 for (int i = 1; i <= n; i++) 199 change(root, pos[i], INF, data[i]); 200 } 201 //返回在lr区间内比x大的数个数 202 int check(int l, int r, int x){ 203 int sum = 0; 204 while (top[l] != top[r]){ 205 //保证永远矮的往上爬 206 if (dep[top[l]] < dep[top[r]]) swap(l, r); 207 sum += query(root, pos[top[l]], pos[l], x); 208 l = fa[top[l]]; 209 } 210 //显然l应该高一点 211 if (dep[l] > dep[r]) swap(l, r); 212 sum += query(root, pos[l], pos[r], x); 213 return sum; 214 } 215 int query(int L, int R, int k){ 216 //首先二分最大值k 217 int Ans, l = -MAX, r = MAX; 218 while (l <= r){ 219 int mid = (l + r) >> 1; 220 if (mid == 3) 221 printf(""); 222 if (check(L, R, mid) >= k) Ans = mid, l = mid + 1; 223 else r = mid - 1; 224 } 225 //printf("%d", check(L, R, 3)); 226 return Ans; 227 } 228 int search(int l, int r){ 229 int sum = 0; 230 while (top[l] != top[r]){ 231 if (dep[top[l]] < dep[top[r]]) swap(l, r); 232 sum += dep[l] - dep[top[l]] + 1; 233 l = fa[top[l]]; 234 } 235 //dep[r]大 236 if (dep[l] > dep[r]) swap(l, r); 237 sum += dep[r] - dep[l] + 1; 238 return sum; 239 } 240 void work(){ 241 for (int i = 1; i <= q; i++){ 242 243 int l, r, k; 244 scanf("%d%d%d", &k, &l, &r); 245 //if (i == 5) 246 //printf("%d", k); 247 if (k == 0){//修改操作 248 change(root, pos[l], data[l], r); 249 data[l] = r; 250 }else{//查询 251 int num = search(l, r);//查询l到r之间的节点个数 252 if (k > num) {printf("invalid request!\n");continue;} 253 printf("%d\n", query(l, r, k)); 254 } 255 } 256 } 257 void debug(){ 258 /*Treap *root = NULL; 259 insert(root, 2); 260 printf("%d", get(root, 2));*/ 261 //printf("%d", search(4, 2)); 262 //for (int i = 1; i <= 5; i++) printf("%d\n", pos[i]); 263 //printf("%d", query(root, 2, 3, 3)); 264 } 265 266 int main(){ 267 //srand(time(0)); 268 269 init(); 270 work(); 271 //debug(); 272 return 0; 273 }