【BZOJ1146】【CTSC2008】网络管理 [整体二分]
网络管理
Time Limit: 50 Sec Memory Limit: 162 MB
[Submit][Status][Discuss]
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大的路由器的延迟时间。
Output
对于每一个第二种询问(k>0),输出一行。
包含一个整数为相应的延迟时间。
如果路径上的路由器不足k个,则输出信息“invalid request!”。
Sample Input
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
2
2
invalid request!
HINT
N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。
对于所有询问满足0<=K<=N。
Main idea
求树上两点路径间第k大的树,需要支持单点修改权值。
Solution
我们一看到这道题,序列的话其实就是BZOJ1901改成求第k大。
我们基于这个思路,从整体二分考虑,然后我们运用树链剖分和线段树。
对于一个点,如果价值>=M的话就把这个点的位置+1权值,然后线段树区间求和就可以找出这个询问 在当前执行的L,M中 有几个>=M的数,由于是树结构,所以这个应该运用树链剖分来在线段树上加。
之后跟静态查询Kth一样判断一下贡献,整体二分继续往下分治即可。
这题思路简单,实现稍微有一点细节需要注意,算是一道经典的数据结构题。\(≧▽≦)/
Code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<map>
using namespace std; const int ONE=;
const int INF=1e8+; int n,m;
int x,y,k;
int a[ONE];
int next[ONE*],first[ONE],go[ONE*],tot;
int Num,res,cnt;
int record[ONE];
int Ans[ONE]; struct power
{
int cnt,opt,cur;
int pos,value;
int l,r,k;
}oper[ONE*],qL[ONE*],qR[ONE*]; struct point
{
int f,son,size,dep;
int top,seg;
}S[ONE]; int get()
{
int res=,Q=;char c;
while( (c=getchar())< || c> )
if(c=='-')Q=-;
res=c-;
while( (c=getchar())>= && c<= )
res=res*+c-;
return res*Q;
} void Add(int u,int v)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v;
next[++tot]=first[v]; first[v]=tot; go[tot]=u;
} namespace Sgt
{
struct power
{
int value;
}Node[ONE*]; void Update(int i,int l,int r,int L,int x)
{
if(l==r)
{
Node[i].value+=x;
return;
} int mid=(l+r)>>;
if(L<=mid) Update(i<<,l,mid,L,x);
else Update(i<<|,mid+,r,L,x);
Node[i].value=Node[i<<].value + Node[i<<|].value;
} void Query(int i,int l,int r,int L,int R)
{
if(L<=l && r<=R)
{
res+=Node[i].value;
return;
} int mid=(l+r)/;
if(L<=mid) Query(i<<,l,mid,L,R);
if(mid+<=R) Query(i<<|,mid+,r,L,R);
}
} namespace Hld
{
void First()
{
S[].top=S[].seg=S[].seg=;
} void Dfs1(int u,int father)
{
S[u].dep=S[father].dep+;
S[u].f=father;
S[u].size=;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father) continue;
Dfs1(v,u);
S[u].size+=S[v].size;
if(S[v].size > S[S[u].son].size) S[u].son=v;
}
} void Dfs2(int u,int father)
{
if(S[u].son)
{
int v=S[u].son;
S[v].top=S[u].top;
S[v].seg=++S[].seg;
Dfs2(v,u);
}
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || S[u].son==v) continue;
S[v].top=v;
S[v].seg=++S[].seg;
Dfs2(v,u);
}
} void Solve(int x,int y)
{
int Tx=S[x].top,Ty=S[y].top;
while(Tx!=Ty)
{
if(S[Tx].dep < S[Ty].dep)
{
swap(x,y);
swap(Tx,Ty);
}
Sgt::Query(,,n,S[Tx].seg,S[x].seg);
x=S[Tx].f;
Tx=S[x].top;
}
if(S[x].dep > S[y].dep) swap(x,y);
Sgt::Query(,,n,S[x].seg,S[y].seg);
}
} void Solve(int l,int r,int L,int R)//第k大
{
if(l>r) return;
if(L==R)
{
for(int i=l;i<=r;i++)
if(oper[i].opt==)
Ans[oper[i].cnt] = L-;
return;
} int M=(L+R)>>; for(int i=l;i<=r;i++)
{
if(oper[i].opt== && oper[i].value>=M)
Sgt::Update(,,n,S[oper[i].pos].seg,);
if(oper[i].opt== && oper[i].value>=M)
Sgt::Update(,,n,S[oper[i].pos].seg,-);
if(oper[i].opt==)
{
res=;
Hld::Solve(oper[i].l,oper[i].r);
record[i] = res;
}
} for(int i=l;i<=r;i++)
{
if(oper[i].opt== && oper[i].value>=M)
Sgt::Update(,,n,S[oper[i].pos].seg,-);
if(oper[i].opt== && oper[i].value>=M)
Sgt::Update(,,n,S[oper[i].pos].seg,);
} int l_num=,r_num=;
for(int i=l;i<=r;i++)
{
if(oper[i].opt!=)
{
if(oper[i].value >= M)
qR[++r_num]=oper[i];
else
qL[++l_num]=oper[i];
}
else
{
if(oper[i].cur + record[i] >= oper[i].k)
qR[++r_num]=oper[i];
else
{
qL[++l_num]=oper[i];
qL[l_num].cur+=record[i];
}
}
} int t=l;
for(int i=;i<=l_num;i++) oper[t++]=qL[i];
for(int i=;i<=r_num;i++) oper[t++]=qR[i]; Solve(l,l+l_num-,L,M);
Solve(l+l_num,r,M+,R);
} int main()
{
n=get(); m=get();
for(int i=;i<=n;i++)
{
a[i]=get();
oper[++cnt].opt=; oper[cnt].pos=i; oper[cnt].value=a[i];
} for(int i=;i<n;i++)
{
x=get(); y=get();
Add(x,y);
} Hld::First();
Hld::Dfs1(,); Hld::Dfs2(,); for(int i=;i<=m;i++)
{
k=get(); x=get(); y=get();
if(k==)
{
oper[++cnt].opt=; oper[cnt].pos=x; oper[cnt].value=a[x];
oper[++cnt].opt=; oper[cnt].pos=x; oper[cnt].value=y;
a[x]=y;
}
else
{
oper[++cnt].opt=; oper[cnt].l=x; oper[cnt].r=y; oper[cnt].k=k;
oper[cnt].cnt=++Num;
}
} Solve(,cnt,,INF); for(int i=;i<=Num;i++)
{
if(Ans[i]!=-) printf("%d",Ans[i]);
else printf("invalid request!");
printf("\n");
}
}
【BZOJ1146】【CTSC2008】网络管理 [整体二分]的更多相关文章
- [BZOJ1146][CTSC2008]网络管理Network(二分+树链剖分+线段树套平衡树)
题意:树上单点修改,询问链上k大值. 思路: 1.DFS序+树状数组套主席树 首先按照套路,关于k大值的问题,肯定要上主席树,每个点维护一棵权值线段树记录它到根的信息. 关于询问,就是Que(u)+Q ...
- [CTSC2008]网络管理 [整体二分]
题面 bzoj luogu 所有事件按时间排序 按值划分下放 把每一个修改 改成一个删除一个插入 对于一个查询 直接查这个段区间有多少合法点 如果查询值大于等于目标值 进入左区间 如果一个查询无解 那 ...
- [BZOJ1146][CTSC2008]网络管理Network
[BZOJ1146][CTSC2008]网络管理Network 试题描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建 ...
- 2019.01.13 bzoj1146: [CTSC2008]网络管理Network(整体二分+树剖)
传送门 题意简述:给一棵树,支持单点修改,询问路径上两点间第kkk大值. 思路: 读懂题之后立马可以想到序列上带修区间kkk大数的整体二分做法,就是用一个bitbitbit来支持查值. 那么这个题把树 ...
- BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链 ...
- BZOJ1146——[CTSC2008]网络管理Network
1.题目大意:就是在动态的树上路径权值第k大. 2.分析:这个就是树链剖分+树套树 #include <cstdio> #include <cstdlib> #include ...
- BZOJ1146[CTSC2008]网络管理——出栈入栈序+树状数组套主席树
题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条 ...
- 【树上莫队】【带修莫队】【权值分块】bzoj1146 [CTSC2008]网络管理Network
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using ...
- 【树链剖分】【函数式权值分块】bzoj1146 [CTSC2008]网络管理Network
裸题,直接上.复杂度O(n*sqrt(n)*log(n)). //Num[i]表示树中的点i在函数式权值分块中对应的点 //Map[i]表示函数式权值分块中的点i在树中对应的点 #include< ...
随机推荐
- 【IIS】 常见问题
[IIS] 常见问题 1. IIS 安装 .Net FrameWork 4.0 开始->所有程序->附件->鼠标右键点击“命令提示符”->以管理员身份运行->%windi ...
- jenkins安全内容配置策略
有时我们使用HTML Publisher Plugin插件时,在jenkins点开html report,会发现没有带任何的css或js样式,这是因为Jenkins 1.641 / Jenkins 1 ...
- Android 上能提高学习工作效率的应用
在知乎上有朋友问 Android 上能提高学习.工作效率的应用有哪些?我给他们的推荐获得了最多赞同.以后会不断完善更新此贴. Any.do :规划日程,各平台都有. Evernote:记笔记,各平台都 ...
- 深入Python的类和对象
多态:不同的子类对象,可以调用相同的父类方法,通过改写父类的方法,产生不同的执行结果 instance和type的区别: instance能够顺延到父类,比对对象与父类是否类型一致.而type只能比对 ...
- python基础篇 08 文件操作
本节主要内容:1. 初识⽂件操作2. 只读(r, rb)3. 只写(w, wb)4. 追加(a, ab)5. r+读写6. w+写读7. a+写读(追加写读)8. 其他操作⽅法9. ⽂件的修改以及另⼀ ...
- kaldi学习 - 一脚本流学习工具使用
目录 yesno训练 先给出整体脚本如下: 分块详解 建立解码脚本 kaldi中脚本东西比较多,一层嵌一层,不易阅读. 本文以yesno为例,直接使用kaldi编译的工具,书写简易训练步骤,方便学习k ...
- lintcode-51-上一个排列
51-上一个排列 给定一个整数数组来表示排列,找出其上一个排列. 注意事项 排列中可能包含重复的整数 样例 给出排列[1,3,2,3],其上一个排列是[1,2,3,3] 给出排列[1,2,3,4],其 ...
- Android调用Java WebSevice篇之二
1.创建Activity. package com.web; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapO ...
- To Chromium之VS调试追踪
启动的code: for(;;){...WaitForWork()}base.dll!base::MessagePumpForUI::DoRunLoop ...
- Byte数据类型—Java
字节与字符 一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节,一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制最小值为0,最大值为255. UTF-8 ...