【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与之相 ...
随机推荐
- 对于利用pca 和 cca 进行fmri激活区识别的理解
1.pca 抛开fmri研究这个范畴,我们有一个超长向量,这个超长向量在fmri研究中,就是体素数据.向量中的每个数值,都代表在相应坐标轴下的坐标值.这些坐标轴所组成的坐标系,其实是标准单位坐标系.向 ...
- URAL1079
Problem E Time Limit : 4000/2000ms (Java/Other) Memory Limit : 32768/16384K (Java/Other) Total Sub ...
- [JIT_APP]Android SQLite简介
SQLite介绍 SQLite是一个非常流行的嵌入式数据库,它支持SQL语言,并且只利用很少的内存就有很好的性能.此外它还是开源的,任何人都可以使用它.许多开源项目(Mozilla, PHP, Pyt ...
- php表单提交方法汇总
问题:网页上提交表单之后,PHP为什么不能获取提交的内容?然而在老版本的PHP上运行却正常. 新版的PHP已经废弃了原来的表单内容处理方式,即不再把提交的表单的内容直接复制到一个同名变量中.解决办法有 ...
- [置顶] SVN服务器搭建和使用
Subversion是优秀的版本控制工具,其具体的的优点和详细介绍,这里就不再多说. 首先来下载和搭建SVN服务器. 现在Subversion已经迁移到apache网站上了,下载地址: http:// ...
- Android实现弹出输入法时,顶部固定,中间部分上移的效果
前言 最近做项目时碰到一个问题,在意见反馈里面,提交按钮写到顶部,当用户输入反馈意见或者邮箱手机号时,弹出的输入法会上移整个页面,导致提交按钮显示不了. 很明显,这样的界面是非常不友好的,找了一些资料 ...
- 微信公众平台--网页授权获取用户基本信息(snsapi_userinfo方式)
关于snsapi_userinfo网页授权的说明 以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的.但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注, ...
- bzoj2822: [AHOI2012]树屋阶梯
咦,这里有好多东西https://en.wikipedia.org/wiki/Catalan_number 每个矩形最多贡献一个拐角 枚举左上角的点和那个拐角是一个矩形 #include<cst ...
- 【设计模式 - 17】之中介者模式(Mediator)
1 模式简介 中介者模式的定义: 用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显式地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互. 中介者模式中的组成部分: 1. ...
- 关于session的实现:cookie与url重写
本文讨论的语境是java EE servlet. 我们都知道session的实现主要两种方式:cookie与url重写,而cookie是首选(默认)的方式,因为各种现代浏览器都默认开通cookie功能 ...