【BZOJ1146】【树链剖分+平衡树】网络管理Network

时间:2023-03-10 00:55:38
【BZOJ1146】【树链剖分+平衡树】网络管理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^8。对于所有询问满足0<=K<=N 。

Source

CTSC2008
【分析】
居然1A了,天不负有心人啊.....写了1个半小时TAT
裸的树上带修改第k大,用树链剖分转成线段树,在每个线段树里面维护一个平衡树。
查找的时候先二分答案,再按照树链剖分的方式找就行了。
发现动态内存分配还是蛮好的,均摊分析,空间复杂度不会爆。
 /*
唐代韦庄
《菩萨蛮·劝君今夜须沈醉》
劝君今夜须沉醉,尊前莫话明朝事。珍重主人心,酒深情亦深。
须愁春漏短,莫诉金杯满。遇酒且呵呵,人生能几何!
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <iomanip>
#include <string>
#include <cmath>
#include <queue>
#include <assert.h>
#include <map>
#include <ctime>
#include <cstdlib>
#include <stack>
#include <set>
#define LOCAL
const int INF = 0x7fffffff;
const int MAXN = + ;
const int maxnode = * + * ;
const int MAXM = + ;
const int MAX = ;
using namespace std;
struct Treap{
int val;
int fix, siz;
Treap *ch[]; void update(){
siz = ;
if (ch[] != NULL) siz += ch[]->siz;
if (ch[] != NULL) siz += ch[]->siz;
}
};
//将t的d儿子换到t
void rotate(Treap *&t, int d){
Treap *p = t->ch[d];
t->ch[d] = p->ch[d ^ ];
t->update();
p->ch[d ^ ] = t;
p->update();
t = p;
return;
}
Treap *NEW(int val){
Treap *t = new Treap;
t->fix = rand();
t->val = val;
t->siz = ;
t->ch[] = t->ch[] = NULL;
return t;
}
void insert(Treap *&t, int val){
if (t == NULL){
t = NEW(val);
return;
}
int d = (val >= t->val);
insert(t->ch[d], val);
if (t->ch[d]->fix > t->fix) rotate(t, d);
t->update();
}
int size(Treap *&t) {return (t == NULL) ? : t->siz;}
//统计比val大的数量,包括val!
int get(Treap *&t, int val){
if (t == NULL) return ;
//右边都比他大..
if (val <= t->val) return size(t->ch[]) + + get(t->ch[], val);
else return get(t->ch[], val);
}
void erase(Treap *&t, int x){
int d;
if (x == t->val) d = -;
else d = (x > t->val);//随意删除一个就行了 if (d == -){
Treap *tmp = t;
if (t->ch[] == NULL){//左儿子为0那么就变成右儿子
t = t->ch[];
delete tmp;
}else if (t->ch[] == NULL){
t = t->ch[];
delete tmp;
}else{//还没到叶子转下去
int f = (t->ch[]->fix > t->ch[]->fix);
rotate(t, f);
erase(t->ch[f ^ ], x);//注意转到另一边了
}
}else erase(t->ch[d], x);
if (t != NULL) t->update();
} //------------------------以上为Treap------------------// struct Node{//线段树的节点
int l, r;
Treap *t;//注意这个里面用动态内存分配...无奈.
Node *ch[];
}*root, mem[MAXN * ];
int n, q;//点数和询问总述数量
int head[MAXN * ], to[MAXN * ];//vector会爆?
int M, next[MAXN * ], fa[MAXN];
int Time, data[MAXN], son[MAXN], siz[MAXN], pos[MAXN];//时间轴
int top[MAXN], tot, dep[MAXN]; void addEdge(int u, int v){
to[M] = v;
next[M]= head[u];
head[u] = M++;
}
void dfs_1(int u){
son[u] = ;
siz[u] = ;
for (int i = head[u];i != -; i = next[i]){
int v = to[i];
if (v == fa[u]) continue;
fa[v] = u;
dep[v] = dep[u] + ;
dfs_1(v);
siz[u] += siz[v];
if (siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs_2(int u, int top_node){
pos[u] = ++Time;
top[u] = top_node;
if (son[u]) dfs_2(son[u], top_node);
for (int i = head[u]; i != -; i = next[i]){
int v = to[i];
if (v == fa[u] || v == son[u]) continue;
dfs_2(v, v);
}
}
Node *NEW(int l, int r){
Node *p = &mem[tot++];
p->l = l;
p->r = r;
p->t = NULL;//p里面的treap
p->ch[] = p->ch[] = NULL;
return p;
}
void build(Node *&t, int l, int r){
if (t == NULL){
t = NEW(l, r);
}
if (l == r) return;
int mid = (l + r) >> ;
build(t->ch[], l, mid);
build(t->ch[], mid + , r);
}
//居然是单点修改OAO
//将l位置的路由器延迟时间由x变为y
void change(Node *&p, int l, int x, int y){
if (p->l == l && p->r == l){
if (x != INF) erase(p->t, x);//为INF的时候就是单纯的插入
insert(p->t, y);
return;
}
if (x != INF) erase(p->t, x);
insert(p->t, y); int mid = (p->l + p->r) >> ;
if (l <= mid) change(p->ch[], l, x, y);
else change(p->ch[], l, x, y);
}
//表示在l,r这一段内比val大的数的个数
int query(Node *&p, int l, int r, int val){
if (l <= p->l && p->r <= r) return get(p->t, val);
int mid = (p->l + p->r) >> ;
int sum = ;
if (l <= mid) sum += query(p->ch[], l, r, val);
if (r > mid) sum += query(p->ch[], l, r, val);
return sum;
}
void init(){
memset(head, -, sizeof(head));
memset(dep, , sizeof(dep));//表示根到自己不包含根的节点数量
siz[] = fa[] = ;
M = Time = ; scanf("%d%d", &n, &q);
for (int i = ; i <= n; i++) scanf("%d", &data[i]);
for (int i = ; i < n; i++){
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v);
addEdge(v, u);
}
dfs_1();
dfs_2(, );
build(root, , Time);
for (int i = ; i <= n; i++)
change(root, pos[i], INF, data[i]);
}
//返回在lr区间内比x大的数个数
int check(int l, int r, int x){
int sum = ;
while (top[l] != top[r]){
//保证永远矮的往上爬
if (dep[top[l]] < dep[top[r]]) swap(l, r);
sum += query(root, pos[top[l]], pos[l], x);
l = fa[top[l]];
}
//显然l应该高一点
if (dep[l] > dep[r]) swap(l, r);
sum += query(root, pos[l], pos[r], x);
return sum;
}
int query(int L, int R, int k){
//首先二分最大值k
int Ans, l = -MAX, r = MAX;
while (l <= r){
int mid = (l + r) >> ;
if (mid == )
printf("");
if (check(L, R, mid) >= k) Ans = mid, l = mid + ;
else r = mid - ;
}
//printf("%d", check(L, R, 3));
return Ans;
}
int search(int l, int r){
int sum = ;
while (top[l] != top[r]){
if (dep[top[l]] < dep[top[r]]) swap(l, r);
sum += dep[l] - dep[top[l]] + ;
l = fa[top[l]];
}
//dep[r]大
if (dep[l] > dep[r]) swap(l, r);
sum += dep[r] - dep[l] + ;
return sum;
}
void work(){
for (int i = ; i <= q; i++){ int l, r, k;
scanf("%d%d%d", &k, &l, &r);
//if (i == 5)
//printf("%d", k);
if (k == ){//修改操作
change(root, pos[l], data[l], r);
data[l] = r;
}else{//查询
int num = search(l, r);//查询l到r之间的节点个数
if (k > num) {printf("invalid request!\n");continue;}
printf("%d\n", query(l, r, k));
}
}
}
void debug(){
/*Treap *root = NULL;
insert(root, 2);
printf("%d", get(root, 2));*/
//printf("%d", search(4, 2));
//for (int i = 1; i <= 5; i++) printf("%d\n", pos[i]);
//printf("%d", query(root, 2, 3, 3));
} int main(){
//srand(time(0)); init();
work();
//debug();
return ;
}