[BZOJ1146][CTSC2008]网络管理Network
[BZOJ1146][CTSC2008]网络管理Network
试题描述
M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门。为了让分布在世界各地的N个
部门之间协同工作,公司搭建了一个连接整个公司的通信网络。该网络的结构由N个路由器和N-1条高速光缆组成。
每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部
门进行通信联络。该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信。 高速光
缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略。但是由于路由器老化,在这些路由器上进行
数据交换会带来很大的延迟。而两个路由器之间的通信延迟时间则与这两个路由器通信路径上所有路由器中最大的
交换延迟时间有关。作为M公司网络部门的一名实习员工,现在要求你编写一个简单的程序来监视公司的网络状况
。该程序能够随时更新网络状况的变化信息(路由器数据交换延迟时间的变化),并且根据询问给出两个路由器通
信路径上延迟第k大的路由器的延迟时间。【任务】 你的程序从输入文件中读入N个路由器和N-1条光缆的连接信息
,每个路由器初始的数据交换延迟时间Ti,以及Q条询问(或状态改变)的信息。并依次处理这Q条询问信息,它们
可能是: 1. 由于更新了设备,或者设备出现新的故障,使得某个路由器的数据交换延迟时间发生了变化。 2. 查
询某两个路由器a和b之间的路径上延迟第k大的路由器的延迟时间。
输入
第一行为两个整数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
输出
对于每一个第二种询问(k>0),输出一行。包含一个整数为相应的延迟时间。如果路径上的路由器不足k个,
则输出信息“invalid request!”(全部小写不包含引号,两个单词之间有一个空格)。
输入示例
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
输出示例
3 2 2 invalid request!
数据规模及约定
见“输入”
题解
树链剖分套线段树套 treap + 二分。4 个 log 爽上天。
本来打了个 1A 的代码,发现它让求第 k “大”而非第 k “小”,而样例给的都是中位数!!!!于是拿黄学长的代码调了半天总是有错发现他数组开小了(那居然还能过!)。我调啊调啊调,改啊改啊改。。。一个上午过去,终于 A 掉了。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 80010 #define maxm 160010 #define maxnode 5440010 struct Node { int v, r, siz; Node() {} Node(int _, int __): v(_), r(__) {} } ns[maxnode]; int ToT, fa[maxnode], ch[2][maxnode]; void maintain(int o) { if(!o) return ; ns[o].siz = 1; for(int i = 0; i < 2; i++) if(ch[i][o]) ns[o].siz += ns[ch[i][o]].siz; return ; } void rotate(int u) { int y = fa[u], z = fa[y], l = 0, r = 1; if(z) ch[ch[1][z]==y][z] = u; if(ch[1][y] == u) swap(l, r); fa[u] = z; fa[y] = u; fa[ch[r][u]] = y; ch[l][y] = ch[r][u]; ch[r][u] = y; maintain(y); maintain(u); return ; } void insert(int& o, int v) { if(!o) { ns[o = ++ToT] = Node(v, rand()); return maintain(o); } bool d = v > ns[o].v; insert(ch[d][o], v); fa[ch[d][o]] = o; if(ns[ch[d][o]].r > ns[o].r) { int t = ch[d][o]; rotate(t); o = t; } return maintain(o); } void del(int& o, int v) { if(!o) return ; if(ns[o].v == v) { if(!ch[0][o] && !ch[1][o]) o = 0; else if(!ch[0][o]) { int t = ch[1][o]; fa[t] = fa[o]; o = t; } else if(!ch[1][o]) { int t = ch[0][o]; fa[t] = fa[o]; o = t; } else { bool d = ns[ch[1][o]].r > ns[ch[0][o]].r; int t = ch[d][o]; rotate(t); o = t; del(ch[d^1][o], v); } } else { bool d = v > ns[o].v; del(ch[d][o], v); } return maintain(o); } int Find(int o, int v) { if(!o) return 0; int rs = ch[1][o] ? ns[ch[1][o]].siz : 0; if(v <= ns[o].v) return rs + 1 + Find(ch[0][o], v); return Find(ch[1][o], v); } int rt[maxn<<2], ql, qr, val[maxn]; void add(int L, int R, int o) { insert(rt[o], val[ql]); if(L == R) return ; int M = L + R >> 1, lc = o << 1, rc = lc | 1; if(ql <= M) add(L, M, lc); else add(M+1, R, rc); return ; } void update(int L, int R, int o, int x) { del(rt[o], val[ql]); insert(rt[o], x); if(L == R) return ; int M = L + R >> 1, lc = o << 1, rc = lc | 1; if(ql <= M) update(L, M, lc, x); else update(M+1, R, rc, x); return ; } int query(int L, int R, int o, int x) { if(ql <= L && R <= qr) return Find(rt[o], x); int M = L + R >> 1, lc = o << 1, rc = lc | 1, ans = 0; if(ql <= M) ans += query(L, M, lc, x); if(qr > M) ans += query(M+1, R, rc, x); return ans; } int n, m, head[maxn], next[maxm], to[maxm], inv[maxn]; void AddEdge(int a, int b) { to[++m] = b; next[m] = head[a]; head[a] = m; swap(a, b); to[++m] = b; next[m] = head[a]; head[a] = m; return ; } int pa[maxn], son[maxn], dep[maxn], siz[maxn], top[maxn], W[maxn], ww; void build(int u) { siz[u] = 1; for(int e = head[u]; e; e = next[e]) if(to[e] != pa[u]) { pa[to[e]] = u; dep[to[e]] = dep[u] + 1; build(to[e]); siz[u] += siz[to[e]]; if(!son[u] || siz[son[u]] < siz[to[e]]) son[u] = to[e]; } return ; } void gett(int u, int tp) { W[u] = ++ww; top[u] = tp; if(son[u]) gett(son[u], tp); for(int e = head[u]; e; e = next[e]) if(to[e] != pa[u] && to[e] != son[u]) gett(to[e], to[e]); return ; } int que(int a, int b, int x) { int f1 = top[a], f2 = top[b], ans = 0; while(f1 != f2) { if(dep[f1] < dep[f2]) swap(f1, f2), swap(a, b); ql = W[f1]; qr = W[a]; ans += query(1, n, 1, x); a = pa[f1]; f1 = top[a]; } if(dep[a] < dep[b]) swap(a, b); ql = W[b]; qr = W[a]; return ans + query(1, n, 1, x); } int main() { n = read(); int q = read(); for(int i = 1; i <= n; i++) inv[i] = read() + 1; for(int i = 1; i < n; i++) { int a = read(), b = read(); AddEdge(a, b); } build(1); gett(1, 1); for(int i = 1; i <= n; i++) val[W[i]] = inv[i]; for(int i = 1; i <= n; i++) ql = i, add(1, n, 1); while(q--) { int k = read(), a = read(), b = read(); if(!k) ql = W[a], update(1, n, 1, b + 1), val[W[a]] = b + 1; else { int l = 0, r = 100000002; while(r - l > 1) { int mid = l + r >> 1; if(que(a, b, mid) < k) r = mid; else l = mid; } if(l) printf("%d\n", l - 1); else puts("invalid request!"); } } return 0; }
代码是挺短的。。。