【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 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

  N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。
  对于所有询问满足0<=K<=N。

Main idea

  求树上两点路径间第k大的树,需要支持单点修改权值。

Source

  我们一看到这道题,序列的话其实就是BZOJ1901改成求第k大。

  我们基于这个思路,从整体二分考虑,然后我们运用树链剖分和线段树。

  对于一个点,如果价值>=M的话就把这个点的位置+1权值,然后线段树区间求和就可以找出这个询问 在当前执行的L,M中 有几个>=M的数,由于是树结构,所以这个应该运用树链剖分来在线段树上加。

  之后跟静态查询Kth一样判断一下贡献,整体二分继续往下分治即可。

  这题思路简单,实现稍微有一点细节需要注意,算是一道经典的数据结构题。\(≧▽≦)/

Code

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cmath>
  8 #include<map>
  9 using namespace std;
 10
 11 const int ONE=160005;
 12 const int INF=1e8+1;
 13
 14 int n,m;
 15 int x,y,k;
 16 int a[ONE];
 17 int next[ONE*2],first[ONE],go[ONE*2],tot;
 18 int Num,res,cnt;
 19 int record[ONE];
 20 int Ans[ONE];
 21
 22 struct power
 23 {
 24         int cnt,opt,cur;
 25         int pos,value;
 26         int l,r,k;
 27 }oper[ONE*10],qL[ONE*10],qR[ONE*10];
 28
 29 struct point
 30 {
 31         int f,son,size,dep;
 32         int top,seg;
 33 }S[ONE];
 34
 35 int get()
 36 {
 37         int res=1,Q=1;char c;
 38         while( (c=getchar())<48 || c>57 )
 39         if(c==‘-‘)Q=-1;
 40         res=c-48;
 41         while( (c=getchar())>=48 && c<=57 )
 42         res=res*10+c-48;
 43         return res*Q;
 44 }
 45
 46 void Add(int u,int v)
 47 {
 48         next[++tot]=first[u];   first[u]=tot;   go[tot]=v;
 49         next[++tot]=first[v];   first[v]=tot;   go[tot]=u;
 50 }
 51
 52 namespace Sgt
 53 {
 54         struct power
 55         {
 56             int value;
 57         }Node[ONE*4];
 58
 59         void Update(int i,int l,int r,int L,int x)
 60         {
 61             if(l==r)
 62             {
 63                 Node[i].value+=x;
 64                 return;
 65             }
 66
 67             int mid=(l+r)>>1;
 68             if(L<=mid) Update(i<<1,l,mid,L,x);
 69             else Update(i<<1|1,mid+1,r,L,x);
 70             Node[i].value=Node[i<<1].value + Node[i<<1|1].value;
 71         }
 72
 73         void Query(int i,int l,int r,int L,int R)
 74         {
 75             if(L<=l && r<=R)
 76             {
 77                 res+=Node[i].value;
 78                 return;
 79             }
 80
 81             int mid=(l+r)/2;
 82             if(L<=mid) Query(i<<1,l,mid,L,R);
 83             if(mid+1<=R) Query(i<<1|1,mid+1,r,L,R);
 84         }
 85 }
 86
 87 namespace Hld
 88 {
 89         void First()
 90         {
 91             S[1].top=S[0].seg=S[1].seg=1;
 92         }
 93
 94         void Dfs1(int u,int father)
 95         {
 96             S[u].dep=S[father].dep+1;
 97             S[u].f=father;
 98             S[u].size=1;
 99             for(int e=first[u];e;e=next[e])
100             {
101                 int v=go[e];
102                 if(v==father) continue;
103                 Dfs1(v,u);
104                 S[u].size+=S[v].size;
105                 if(S[v].size > S[S[u].son].size) S[u].son=v;
106             }
107         }
108
109         void Dfs2(int u,int father)
110         {
111             if(S[u].son)
112             {
113                 int v=S[u].son;
114                 S[v].top=S[u].top;
115                 S[v].seg=++S[0].seg;
116                 Dfs2(v,u);
117             }
118             for(int e=first[u];e;e=next[e])
119             {
120                 int v=go[e];
121                 if(v==father || S[u].son==v) continue;
122                 S[v].top=v;
123                 S[v].seg=++S[0].seg;
124                 Dfs2(v,u);
125             }
126         }
127
128         void Solve(int x,int y)
129         {
130             int Tx=S[x].top,Ty=S[y].top;
131             while(Tx!=Ty)
132             {
133                 if(S[Tx].dep < S[Ty].dep)
134                 {
135                     swap(x,y);
136                     swap(Tx,Ty);
137                 }
138                 Sgt::Query(1,1,n,S[Tx].seg,S[x].seg);
139                 x=S[Tx].f;
140                 Tx=S[x].top;
141             }
142             if(S[x].dep > S[y].dep) swap(x,y);
143             Sgt::Query(1,1,n,S[x].seg,S[y].seg);
144         }
145 }
146
147 void Solve(int l,int r,int L,int R)//第k大
148 {
149         if(l>r) return;
150         if(L==R)
151         {
152             for(int i=l;i<=r;i++)
153             if(oper[i].opt==3)
154             Ans[oper[i].cnt] = L-1;
155             return;
156         }
157
158         int M=(L+R)>>1;
159
160         for(int i=l;i<=r;i++)
161         {
162             if(oper[i].opt==1 && oper[i].value>=M)
163                 Sgt::Update(1,1,n,S[oper[i].pos].seg,1);
164             if(oper[i].opt==2 && oper[i].value>=M)
165                 Sgt::Update(1,1,n,S[oper[i].pos].seg,-1);
166             if(oper[i].opt==3)
167             {
168                 res=0;
169                 Hld::Solve(oper[i].l,oper[i].r);
170                 record[i] = res;
171             }
172         }
173
174         for(int i=l;i<=r;i++)
175         {
176             if(oper[i].opt==1 && oper[i].value>=M)
177                 Sgt::Update(1,1,n,S[oper[i].pos].seg,-1);
178             if(oper[i].opt==2 && oper[i].value>=M)
179                 Sgt::Update(1,1,n,S[oper[i].pos].seg,1);
180         }
181
182         int l_num=0,r_num=0;
183         for(int i=l;i<=r;i++)
184         {
185             if(oper[i].opt!=3)
186             {
187                 if(oper[i].value >= M)
188                     qR[++r_num]=oper[i];
189                 else
190                     qL[++l_num]=oper[i];
191             }
192             else
193             {
194                 if(oper[i].cur + record[i] >= oper[i].k)
195                     qR[++r_num]=oper[i];
196                 else
197                 {
198                     qL[++l_num]=oper[i];
199                     qL[l_num].cur+=record[i];
200                 }
201             }
202         }
203
204         int t=l;
205         for(int i=1;i<=l_num;i++) oper[t++]=qL[i];
206         for(int i=1;i<=r_num;i++) oper[t++]=qR[i];
207
208         Solve(l,l+l_num-1,L,M);
209         Solve(l+l_num,r,M+1,R);
210 }
211
212 int main()
213 {
214         n=get();    m=get();
215         for(int i=1;i<=n;i++)
216         {
217             a[i]=get();
218             oper[++cnt].opt=1;  oper[cnt].pos=i;    oper[cnt].value=a[i];
219         }
220
221         for(int i=1;i<n;i++)
222         {
223             x=get();    y=get();
224             Add(x,y);
225         }
226
227         Hld::First();
228         Hld::Dfs1(1,0); Hld::Dfs2(1,0);
229
230         for(int i=1;i<=m;i++)
231         {
232             k=get();    x=get();    y=get();
233             if(k==0)
234             {
235                 oper[++cnt].opt=2;  oper[cnt].pos=x;    oper[cnt].value=a[x];
236                 oper[++cnt].opt=1;  oper[cnt].pos=x;    oper[cnt].value=y;
237                 a[x]=y;
238             }
239             else
240             {
241                 oper[++cnt].opt=3;  oper[cnt].l=x;  oper[cnt].r=y;  oper[cnt].k=k;
242                 oper[cnt].cnt=++Num;
243             }
244         }
245
246         Solve(1,cnt,0,INF);
247
248         for(int i=1;i<=Num;i++)
249         {
250             if(Ans[i]!=-1) printf("%d",Ans[i]);
251             else printf("invalid request!");
252             printf("\n");
253         }
254 }

时间: 2024-10-14 02:00:22

【BZOJ1146】【CTSC2008】网络管理 [整体二分]的相关文章

[CTSC2008]网络管理 [整体二分]

题面 bzoj luogu 所有事件按时间排序 按值划分下放 把每一个修改 改成一个删除一个插入 对于一个查询 直接查这个段区间有多少合法点 如果查询值大于等于目标值 进入左区间 如果一个查询无解 那么它要求第k大无解 k > 路径长 用lca维护即可 #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <cstring> #

[BZOJ1146]CTSC2008网络管理|树上带修改K大

树上带修改K大,太可怕..写了树链剖分+线段树套平衡树+二分和dfs序+主席树两种,每种都是写+调试花了将近5个小时!!我实在是太弱了.. 1.   树链剖分+线段树套平衡树+二分 最显然的做法了,没啥好多说的,不过写起来真是麻烦(我太弱), 一不小心就会把线段树和平衡树的节点的域弄混,犯了超级多傻逼错误..写这题的时候还把自己树链剖分的风格改了一下,以前的实在是太麻烦了..查询的时候二分答案,统计比当前的k大的数有多少个就行了.. 2.   dfs序+主席树 考虑不带修改,那么可以对每个节点维

BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链上的第k大值 题解 水题. 就是烦了一点. 树链剖分+带修主席树. 带修主席树: BZOJ1901 Zju2112 Dynamic Rankings 主席树 代码 #include <cstring> #include <cstdio> #include <algorithm&g

bzoj1146 [CTSC2008]网络管理Network

Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由

【树链剖分】【函数式权值分块】bzoj1146 [CTSC2008]网络管理Network

裸题,直接上.复杂度O(n*sqrt(n)*log(n)). //Num[i]表示树中的点i在函数式权值分块中对应的点 //Map[i]表示函数式权值分块中的点i在树中对应的点 #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 80001 #define INF 2147483647 #define NN 87001 #define BN 296 int

[CTSC2008]网络管理(整体二分+树剖+树状数组)

一道经典的带修改树链第 \(k\) 大的问题. 我只想出三个 \(\log\) 的解法... 整体二分+树剖+树状数组. 那不是暴力随便踩的吗??? 不过跑得挺快的. \(Code\ Below:\) // luogu-judger-enable-o2 #include <bits/stdc++.h> #define lowbit(x) ((x)&(-(x))) using namespace std; const int maxn=80000+10; const int lim=1e

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

bzoj1146整体二分+树链剖分+树状数组

其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 inline int read() 7 { 8 int x=0,f=1,ch=getchar(); 9 while(ch<

bzoj 1146 网络管理Network (CDQ 整体二分 + 树刨)

题目传送门 题意:求树上路径可修改的第k大值是多少. 题解:CDQ整体二分+树刨. 每一个位置上的数都会有一段持续区间 根据CDQ拆的思维,可以将这个数拆成出现的时间点和消失的时间点. 然后通过整体二分第k大思路 + 树炮询问路径上出现点的个数就好了. 说一下整体二分的思路. 先假设第k大的值是mid, 然后按照时间顺序,出现一个数<=mid标记这个数的位置为1, 消失一个数<=mid,标记这个数的位置为0. 然后对于询问来说,询问路径上的值, 与 k进行比较, 如果 值 >= k则说明