【BZOJ 1146】网络管理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

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 }
时间: 2024-10-12 14:43:54

【BZOJ 1146】网络管理Network的相关文章

[BZOJ 1146]网络管理Network 树上带修改路径k值

题目意思非常清楚,就是要求树上带修改的路径k大值 如果不带修改的话,我会用树上主席树去搞,以父子关系建树,可以参见 [BZOJ 3123]森林 但是带修改就不会打了QAQ,于是去学了另一种在dfs序上搞的方法(同时感谢呵呵酵母菌的帮助) 其实思想是一样的,就是搞出来节点到根路径的线段树,然后用x+y-lca-fa(lca)去差分出来树上路径的线段树,再去里面查询k值 那么我们怎么得到点到根路径的线段树呢?可以在dfs序上差分啊! dfs序列上的dfnl[x]~dfnr[x]包含的是以x为根节点的

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

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

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

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

【BZOJ 1146】 [CTSC2008]网络管理Network

1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MB Submit: 1938  Solved: 577 [Submit][Status] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机

BZOJ 1146: [CTSC2008]网络管理Network [树上带修改主席树]

1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3522  Solved: 1041[Submit][Status][Discuss] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成. 每个部门都有一个专属的路由器,

BZOJ 1146: [CTSC2008]网络管理Network( 树链剖分 + 树状数组套主席树 )

树链剖分完就成了一道主席树裸题了, 每次树链剖分找出相应区间然后用BIT+(可持久化)权值线段树就可以完成计数. 但是空间问题很严重....在修改时不必要的就不要新建, 直接修改原来的..详见代码. 时间复杂度O(N*log^3(N)) ---------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<

BZOJ 1146: [CTSC2008]网络管理Network

1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3539  Solved: 1054[Submit][Status][Discuss] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成. 每个部门都有一个专属的路由器,

【BZOJ 1146】【CTSC 2008】网络管理network

一句话题意,树链上带改动区间第k大 感觉能够dfs+主席树O(nlog2n)过掉,但我不会写= = 于是写的线段树套平衡树+链剖+二分(改动O(nlog3n),查询O(nlog4n)慢了好多啊QAQ) 这里简介一下区间第K大做法.对于每一个线段树所"管辖"的范围,建一棵相应范围内的平衡树(我用的Treap):改动时,改动每一个包括被改动节点的线段树节点所相应的Treap.查询时.二分 答案.统计每一个区间内比当前答案小的数就可以(为了保证是序列里的数.我们能够二分答案在原序列中排名)

BZOJ 1146 CTSC 2008 网络管理 Network 树链剖分+二分答案+平衡树

题目大意:有n个路由器,他们由n-1条边连接(形成一棵树).每一个路由器有一个延时值.有两种操作: 1.查询树上x,y两点之间的路径上第k大的权值是多少 2.修改x位置的权值为y 思路:当我大概想到怎么做这个题的时候,所想的时间复杂度已经达到了O(nlog^4n),偷偷的瞄了一眼数据范围...(N,Q<=80000,时限50s,小心翼翼的掏出计算器算了一下:8w * log(8w) ^  4 ≈ 56E,心中这样想着:Treap有常数,链剖常数大,二分不稳定的范围好像不止8w...评测机会不会很