码迷,mamicode.com
首页 > Web开发 > 详细

【BZOJ 1146】网络管理Network

时间:2015-07-02 13:31:17      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:

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

10% 测试数据满足N<=8000,Q<=3000,

40% 测试数据满足所有询问中1<=K<=5 。即路由器的延迟时间不会发生变化。

100% 测试数据满足N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。对于所有询问满足0<=K<=N 。
 
分析:
  树上路径第K大带修改,实际上就是BZOJ 2588 + BZOJ 1901,用树状数组套主席树。
  根据DFS序将节点放入树状数组,则每个节点及其子树都对应树状数组上的一段,把树状数组差分来看,一个节点对应的主席树版本就是它的前缀和主席树,每次修改子树,就是修改一段区间[l,r],而差分之后只要修改l和r+1就好了。
  查询的时候,找四个主席树版本(树状数组上的前缀和),节点A、B,和节点A、B的LCA以及LCA的父亲,然后随便搞就好了。
 
代码:
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 
  5 #define rint register int
  6 
  7 int n, q, u, v, pow[100000];
  8 int k[100000], a[100000], b[100000];
  9 int begin[100000], end[100000];
 10 int fa[100000][22], depth[100000];
 11 
 12 char ch,B[1<<15],*S=B,*T=B,buf[1<<21],*O=buf,stk[40];
 13 #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
 14 inline const int getint() //输入优化
 15 {
 16     char c = getc();
 17     rint k = 1, r = 0;
 18     for(; c < 0 || c > 9; c = getc())
 19         if(c == -) k = -1;
 20     for(; c >= 0 && c <= 9; c = getc())
 21         r = r * 10 + c - 0;
 22     return k * r;
 23 }
 24 
 25 int lca(rint x, rint y) //找LCA
 26 {
 27     rint i;
 28     if (depth[x] < depth[y])
 29         x ^= y, y ^= x, x ^= y;
 30     for (i = fa[x][21]; depth[x] > depth[y]; i--)
 31         if (depth[fa[x][i]] >= depth[y]) x = fa[x][i];
 32     if (x == y) return x;
 33     for (i = fa[x][21]; i >= 0; i--)
 34         if (fa[x][i] != fa[y][i])
 35             x = fa[x][i], y = fa[y][i];
 36     return fa[x][0];
 37 
 38 }
 39 
 40 /*********edges**********/
 41 int ep[200000], et[200000];
 42 int last[100000], en;
 43 
 44 inline void addedge(rint f, rint t) //邻接表
 45 {
 46     en++;
 47     ep[en] = last[f];
 48     last[f] = en;
 49     et[en] = t;
 50 }
 51 
 52 /*****Discretization*****/
 53 int num[200000], count;
 54 
 55 int lb(rint key) // lower_bound
 56 {
 57     rint l = 1, r = count, mid;
 58     while (l < r)
 59     {
 60         mid = l + r >> 1;
 61         if (num[mid] == key)
 62             return mid;
 63         if (num[mid] < key)
 64             l = mid + 1;
 65         else r = mid - 1;
 66     }
 67     return l;
 68 }
 69 
 70 void discretizate() //离散化
 71 {
 72     std::sort(num + 1, num + count + 1);
 73     rint tmp = 0, i;
 74     num[++count] = 1000000013;
 75     for (i = 1; i <= count; i++)
 76     {
 77         if (num[i] != num[i + 1])
 78             num[++tmp] = num[i];
 79     }
 80     count = tmp;
 81     for (i = 1; i <= n; i++)
 82     {
 83         pow[i] = lb(pow[i]);
 84     }
 85 }
 86 
 87 /********ZX-Tree*********/
 88 int nls[10000000], nrs[10000000], nsum[10000000];
 89 
 90 int ns, tmpos, tmdata;
 91 
 92 void tmodify(int &t, rint left, rint right) //主席树上修改
 93 {
 94     if (t == 0)
 95     {
 96         nsum[t = ++ns] = 0;
 97     }
 98     if (left < right)
 99     {
100         int mid = left + right >> 1;
101         if (tmpos <= mid) tmodify(nls[t], left, mid);
102         else tmodify(nrs[t], mid + 1, right);
103         nsum[t] += tmdata;
104     } else nsum[t] += tmdata;
105 }
106 
107 /*******tree-array*******/
108 int root[100000], rts;
109 
110 void modify(rint x, rint y, rint pos, rint data) //树状数组上修改一段区间
111 {
112     tmpos = pos, tmdata = data;
113     for (; x <= n; x += x & -x)
114         tmodify(root[x], 1, count);
115     tmdata = -data;
116     for (y++; y <= n; y += y & -y)
117         tmodify(root[y], 1, count);
118 }
119 
120 int rs[4][30];
121 
122 int init_rs(rint i, rint x) //用rs数组记录查询时需要用到的点
123 {
124     memset(rs[i], 0, sizeof (rs[i]));
125     int ret = 0;
126     for (; x > 0; x -= x & -x)
127     {
128         rs[i][++rs[i][0]] = root[x];
129         ret += nsum[root[x]];
130     }
131     return ret;
132 }
133 
134 int query_rs() //查询每个点右儿子的大小
135 {
136     int ret = 0; rint i;
137     for (i = 1; i <= rs[0][0]; i++)
138         ret += nsum[nrs[rs[0][i]]];
139     for (i = 1; i <= rs[1][0]; i++)
140         ret += nsum[nrs[rs[1][i]]];
141     for (i = 1; i <= rs[2][0]; i++)
142         ret -= nsum[nrs[rs[2][i]]];
143     for (i = 1; i <= rs[3][0]; i++)
144         ret -= nsum[nrs[rs[3][i]]];
145     return ret;
146 }
147 
148 void down(rint d) //将每个点变成它的左/右儿子
149 {
150     rint x, i;
151     for (x = 0; x < 4; x++)
152         for (i = 1; i <= rs[x][0]; i++)
153             rs[x][i] = d ? nrs[rs[x][i]] : nls[rs[x][i]];
154 }
155 
156 int query(rint x, rint y, rint data) //查询
157 {
158     int s = 0, f = lca(x, y), mid;
159     s += init_rs(0, begin[x]);
160     s += init_rs(1, begin[y]);
161     s -= init_rs(2, begin[f]);
162     s -= init_rs(3, begin[fa[f][0]]);
163     if (s < data) return -1;
164     int left = 1, right = count;
165     while (left < right) //迭代
166     {
167         mid = left + right >> 1;
168         s = query_rs();
169         if (data > s)
170         {
171             down(0);
172             right = mid;
173             data -= s;
174         }
175         else
176         {
177             down(1);
178             left = mid + 1;
179         }
180     }
181     return num[left];
182 }
183 
184 /**********dfs***********/
185 void DFS(rint x) //找出dfs序和求lca的rmq数组
186 {
187     rint i;
188     depth[x] = depth[fa[x][0]] + 1;
189     for (i = 0; fa[x][i]; fa[x][21] = ++i)
190         fa[x][i + 1] = fa[fa[x][i]][i];
191     begin[x] = ++rts;
192     root[begin[x]] = ++ns;
193     for (i = last[x]; i; i = ep[i])
194         if (begin[et[i]] == 0)
195             fa[et[i]][0] = x, DFS(et[i]);
196     end[x] = rts;
197 }
198 
199 int main()
200 {
201     n = getint();
202     q = getint();
203     count = 0;
204     rint i, tmp;
205     for (i = 1; i <= n; i++)
206         num[++count] = pow[i] = getint();
207     for (i = 1; i < n; i++)
208     {
209         u = getint();
210         v = getint();
211         addedge(u, v);
212         addedge(v, u);
213     }
214     for (i = 1; i <= q; i++)
215     {
216         k[i] = getint();
217         a[i] = getint();
218         b[i] = getint();
219         if (k[i] == 0) num[++count] = b[i];
220     }
221     discretizate();
222     DFS(1);
223     for (i = 1; i <= n; i++)
224     {
225         modify(begin[i], end[i], pow[i], 1);
226     }
227     for (i = 1; i <= q; i++)
228     {
229         if (k[i])
230         {
231             tmp = query(a[i], b[i], k[i]);
232             if (tmp >= 0) printf("%d\n", tmp);
233             else printf("invalid request!\n");
234         }
235         else
236         {
237             modify(begin[a[i]], end[a[i]], pow[a[i]], -1);
238             pow[a[i]] = lb(b[i]);
239             modify(begin[a[i]], end[a[i]], pow[a[i]], 1);
240         }
241     }
242 }

 

【BZOJ 1146】网络管理Network

标签:

原文地址:http://www.cnblogs.com/lightning34/p/4615593.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!