【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
Source
/*
唐代韦庄
《菩萨蛮·劝君今夜须沈醉》
劝君今夜须沉醉,尊前莫话明朝事。珍重主人心,酒深情亦深。
须愁春漏短,莫诉金杯满。遇酒且呵呵,人生能几何!
*/
#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 ;
}
【BZOJ1146】【树链剖分+平衡树】网络管理Network的更多相关文章
- [BZOJ1146][CTSC2008]网络管理Network(二分+树链剖分+线段树套平衡树)
题意:树上单点修改,询问链上k大值. 思路: 1.DFS序+树状数组套主席树 首先按照套路,关于k大值的问题,肯定要上主席树,每个点维护一棵权值线段树记录它到根的信息. 关于询问,就是Que(u)+Q ...
- BZOJ 1146: [CTSC2008]网络管理Network 树链剖分+线段树+平衡树
1146: [CTSC2008]网络管理Network Time Limit: 50 Sec Memory Limit: 162 MBSubmit: 870 Solved: 299[Submit] ...
- BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链 ...
- BZOJ 1146: [CTSC2008]网络管理Network( 树链剖分 + 树状数组套主席树 )
树链剖分完就成了一道主席树裸题了, 每次树链剖分找出相应区间然后用BIT+(可持久化)权值线段树就可以完成计数. 但是空间问题很严重....在修改时不必要的就不要新建, 直接修改原来的..详见代码. ...
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
- BZOJ3159决战——树链剖分+非旋转treap(平衡树动态维护dfs序)
题目描述 输入 第一行有三个整数N.M和R,分别表示树的节点数.指令和询问总数,以及X国的据点. 接下来N-1行,每行两个整数X和Y,表示Katharon国的一条道路. 接下来M行,每行描述一个指令或 ...
- bzoj1146整体二分+树链剖分+树状数组
其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 #include<cstdio> #include<cstr ...
- HDU - 6393 Traffic Network in Numazu(树链剖分+基环树)
http://acm.hdu.edu.cn/showproblem.php?pid=6393 题意 给n个点和n条边的图,有两种操作,一种修改边权,另一种查询u到v的最短路. 分析 n个点和n条边,实 ...
- hdu 6393 Traffic Network in Numazu (树链剖分+线段树 基环树)
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6393 思路:n个点,n条边,也就是基环树..因为只有一个环,我们可以把这个环断开,建一个新的点n+1与之相 ...
随机推荐
- 【转】Android--UI之ProgressBar--不错
原文网址:http://www.cnblogs.com/plokmju/p/android_progressbar.html 前言 开门见山,开篇明意.这篇博客主要讲解一下Android中Progre ...
- HDOJ/HDU 2568 前进(简单题)
Problem Description 轻松通过墓碑,进入古墓后,才发现里面别有洞天. 突然,Yifenfei发现自己周围是黑压压的一群蝙蝠,个个扇动翅膀正准备一起向他发起进攻! 形势十分危急! 好在 ...
- vijosP1071 新年趣事之打牌
vijosP1071 新年趣事之打牌 链接:https://vijos.org/p/1071 [思路] 01背包+路径输出. 用d[][]记录[][]可转移的数目,>=2则输出-1,0输出0,否 ...
- Fzu Problem 2082 过路费 LCT,动态树
题目:http://acm.fzu.edu.cn/problem.php?pid=2082 Problem 2082 过路费 Accept: 528 Submit: 1654Time Limit ...
- hdoj 1045 Fire Net
Fire Net Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- Oracle RAC中的投票算法
RAC集群中有三台机器,A,B,C A,B,C都会有3票,假设这是A的心跳线出现问题,整个RAC集群就划分为两个paritition, 一个是只有A的partition,一个是B,C组成的partit ...
- Docker官方文档翻译之入门
转自:http://www.cnblogs.com/vikings-blog/p/3958091.html Docker学习总结之docker入门 Understanding Docker 以下均翻译 ...
- redis中各种数据类型对应的jedis操作命令
redis中各种数据类型对应的jedis操作命令 一.常用数据类型简介: redis常用五种数据类型:string,hash,list,set,zset(sorted set). 1.String类型 ...
- 【Android - 框架】之Fresco的使用
当下有很多图片加载框架,常见的有Glide.Fresco.Picasso等.Glide因为其体积小.缓存机制强大等优点,受到了广大程序员的青睐:Fresco虽然体积比较大,缓存机制也没有Glide强大 ...
- TreeComboBox控件范例
本文转载:http://www.cnblogs.com/hoodlum1980/archive/2008/01/30/1058140.html 在我印象中有很多各种各样的自定义控件(例如TreeLis ...