【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与之相 ...
随机推荐
- Camus导入中文乱码问题(源码修改、编译、部署、任务启动)
Camus使用过程中业务方反映从Kafka导入至HDFS中的数据有中文乱码问题,且业务方确认写入的数据编码为UTF-8,开始跟进. 问题重现: (1)编写代码将带有中文的字符串以编码UTF-8 ...
- unity3d 随机生成地形之随机山脉
利用Fractal Noise生成地形,再加上山体shader,外加雪shader Noise生成结果 noise 生成主要参考这篇文章,就不再赘述 Value3D: Perlin2D: Fracta ...
- Google改变生活
前言 前天,在图书馆,无意之中,发现这本书,特写博客来与各位前来下榻本园的博友们,分享和学习! 本博文的主要内容有: 参考此书.感谢韩梅编者,出于此,我写本博文为了方便日后自己的查阅使用和来我园的共 ...
- thinkphp I方法取传参
/** * 获取输入参数 支持过滤和默认值 * 使用方法: * <code> * I('id',0); 获取id参数 自动判断get或者post * I('post.name','','h ...
- 平时Error记录
The Windows Firewall on this machine is currently 1.This row already belongs to another table. DataT ...
- servlet清晰理解
servlet介绍 Servlet看起来像是通常的Java程序.它是JSP的前身,在MVC架构中担任Controller的角色,即控制层.主要进行数据的处理操作和流程的控制,并将有关结果存储到Java ...
- SpringMVC DispatcherServlet 说明与web配置
使用Spring MVC,配置DispatcherServlet是第一步. DispatcherServlet是一个Servlet,所以能够配置多个DispatcherServlet. Dispatc ...
- ref和out的区别在c#中 总结
ref 关键字使参数按引用传递.其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中.简单点说就是,使用了ref和out的效果就几乎和C中使用了指针变量一样.它能够让你 ...
- 使用SqlAlchemy时如何方便的取得dict数据、dumps成Json
使用Sqlalchemy可以方便的从数据库读取出python对象形式的数据(吐槽:说实话对象形式也没多方便,还不如我之前从关系型数据库直接读取出dict形式的数据用起来方便,具体参见我以前的文章htt ...
- 使用java注解的例子有没有
使用java注解的例子 参考文档:http://www.cnblogs.com/pepcod/archive/2013/02/20/2918719.html http://www.shaoqun.co ...