BZOJ 1146: [CTSC2008]网络管理Network

1146: [CTSC2008]网络管理Network

Time Limit: 50 Sec  Memory Limit: 162 MB
Submit: 3539  Solved: 1054
[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大的路由器的延迟时间。注意N

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

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

[Submit][Status][Discuss]

本来以为是CDQ什么的,发现并不会;从DaD3zZ神犇那里看到带修主席树,表示也不会。

然后就是看代码学喽,各种RE各种WA,外加OJ上的TLE。直到代码长的都一模一样了才过,T_T,看来还有重新学习的必要。

DaD3zZ的题解,摘抄在下——

这道题方法很好想把,树上带修第k大问题,最直观的就是树链剖分+树套树,复杂度O(Nlog^4N),我是直接 dfs序+带修主席树 硬上,复杂度是O(Nlog^2N)

问题在于内存 ,所以可以考虑先建一棵完整的树,然后树状数组修改时只搞一条链这样能把内存大大降低。

并且,这里的dfs序直接用就好了,并不需要搞成入栈出栈序,那样内存消耗依旧很大,自己第一次大概是180M--MLE。

By DaD3zZ

另外记录一下带修主席树的大体思想:

一般主席树维护的是前缀关系,即 $Root_{i}$ 上含有从$1$到$i$的区间内的信息,而这样是不能修改的,因为改动区间中一个地方的信息,就需要把后面所有地方的 $Root_{j},i \leq j \leq n$ 全部修改。

带修主席树利用树状数组的形式,每个 $Root_{i}$ 上维护的只有树状数组上 $i$ 这个位置管辖的区间,这样更改区间中一处位置,只需要更改其在树状数组上的所有祖先节点,这是 $log_{2}N$ 级别的,所以总体复杂度是 $O(log_{2}^{2}N)$ 的。

而查询的时候,先开两个存放根节点的数组,分别为 $Add$ 和 $Sub$ ,代表需要加上$Add$中节点上的答案,减去$Sub$中节点上的答案。这个还好理解,原本主席树就是用 $Root_{i}$ 的答案减去 $Root_{j}$ 的答案从而得到 $(j,i]$ 这一区间的答案的,现在因为外层还有树状数组,所以 $i$ 和 $j$ 不唯一了,分别变为了一些结点。权值线段树上二分的时候还是类似,只是需要从多个 $Root$ 中计算出左(右)侧答案,进而判断应该向左还是右递归。注意递归的时候需要把所有 $Add$ 和 $Sub$ 中的结点向该方向递归。

  1 #include <cstdio>
  2 #include <vector>
  3 #include <algorithm>
  4
  5 inline int nextChar(void)
  6 {
  7     const static int siz = 1024;
  8
  9     static char buf[siz];
 10     static char *hd = buf + siz;
 11     static char *tl = buf + siz;
 12
 13     if (hd == tl)
 14         fread(hd = buf, 1, siz, stdin);
 15
 16     return *hd++;
 17 }
 18
 19 inline int nextInt(void)
 20 {
 21     register int ret = 0;
 22     register int neg = false;
 23     register int bit = nextChar();
 24
 25     for (; bit < 48; bit = nextChar())
 26         if (bit == ‘-‘)neg ^= true;
 27
 28     for (; bit > 47; bit = nextChar())
 29         ret = ret * 10 + bit - 48;
 30
 31     return neg ? -ret : ret;
 32 }
 33
 34 const int siz = 80005;
 35
 36 int N, M;
 37
 38 int tim[siz];
 39
 40 int map[siz << 1], tot;
 41
 42 int opt[siz], opx[siz], opy[siz];
 43
 44 int edges;
 45 int hd[siz];
 46 int to[siz << 1];
 47 int nt[siz << 1];
 48
 49 inline void addEdge(int x, int y)
 50 {
 51     nt[edges] = hd[x]; to[edges] = y; hd[x] = edges++;
 52     nt[edges] = hd[y]; to[edges] = x; hd[y] = edges++;
 53 }
 54
 55 int dfn;
 56 int arv[siz];
 57 int lev[siz];
 58 int dep[siz];
 59 int fa[siz][17];
 60
 61 void preworkDFS(int u, int f)
 62 {
 63     arv[u] = ++dfn;
 64
 65     for (int i = 1; i <= 16; ++i)
 66         fa[u][i] = fa[fa[u][i - 1]][i - 1];
 67
 68     for (int i = hd[u], v; ~i; i = nt[i])
 69         if ((v = to[i]) != f)
 70         {
 71             fa[v][0] = u;
 72             dep[v] = dep[u] + 1;
 73             preworkDFS(v, u);
 74         }
 75
 76     lev[u] = dfn + 1;
 77 }
 78
 79 inline int lca(int a, int b)
 80 {
 81     if (dep[a] < dep[b])
 82         a ^= b ^= a ^= b;
 83
 84     for (int i = 16; i >= 0; --i)
 85         if (dep[fa[a][i]] >= dep[b])
 86             a = fa[a][i];
 87
 88     if (a == b)return a;
 89
 90     for (int i = 16; i >= 0; --i)
 91         if (fa[a][i] != fa[b][i])
 92             a = fa[a][i], b = fa[b][i];
 93
 94     return fa[a][0];
 95 }
 96
 97 int cnt;
 98 int root[siz];
 99 int ls[siz * 80];
100 int rs[siz * 80];
101 int sm[siz * 80];
102
103 std::vector<int> add;
104 std::vector<int> sub;
105
106 inline void clear(void)
107 {
108     add.clear();
109     sub.clear();
110 }
111
112 void insert(int l, int r, int &t, int f, int p, int v)
113 {
114     t = ++cnt;
115
116     ls[t] = ls[f];
117     rs[t] = rs[f];
118
119     sm[t] = sm[f] + v;
120
121     if (l != r)
122     {
123         int mid = (l + r) >> 1;
124
125         if (p <= mid)
126             rs[t] = rs[f], insert(l, mid, ls[t], ls[f], p, v);
127         else
128             ls[t] = ls[f], insert(mid + 1, r, rs[t], rs[f], p, v);
129     }
130 }
131
132 int query(int l, int r, int k)
133 {
134     if (l == r)return l;
135
136     int mid = (l + r) >> 1, sn = 0, sr = 0;
137
138     for (int i = 0; i < add.size(); ++i)sr += sm[rs[add[i]]], sn += sm[add[i]];
139     for (int i = 0; i < sub.size(); ++i)sr -= sm[rs[sub[i]]], sn -= sm[sub[i]];
140
141     if (sn < k)
142         return -1;
143     if (sr < k)
144     {
145         for (int i = 0; i < add.size(); ++i)add[i] = ls[add[i]];
146         for (int i = 0; i < sub.size(); ++i)sub[i] = ls[sub[i]];
147
148         return query(l, mid, k - sr);
149     }
150     else
151     {
152         for (int i = 0; i < add.size(); ++i)add[i] = rs[add[i]];
153         for (int i = 0; i < sub.size(); ++i)sub[i] = rs[sub[i]];
154
155         return query(mid + 1, r, k);
156     }
157 }
158
159 int bit[siz];
160
161 inline void modify(int t, int p, int d)
162 {
163     for (int i = t; i <= dfn; i += i&-i)
164         insert(1, tot, bit[i], bit[i], p, d);
165 }
166
167 inline void addQuery(int t)
168 {
169     add.push_back(root[t]);
170
171     for (int i = arv[t]; i; i -= i&-i)
172         add.push_back(bit[i]);
173 }
174
175 inline void subQuery(int t)
176 {
177     sub.push_back(root[t]);
178
179     for (int i = arv[t]; i; i -= i&-i)
180         sub.push_back(bit[i]);
181 }
182
183 void buildDFS(int u, int f)
184 {
185     insert(1, tot, root[u], root[f], tim[u], 1);
186
187     for (int i = hd[u]; ~i; i = nt[i])
188         if (to[i] != f)buildDFS(to[i], u);
189 }
190
191 signed main(void)
192 {
193     N = nextInt();
194     M = nextInt();
195
196     for (int i = 0; i <= N; ++i)
197         hd[i] = -1;
198
199     for (int i = 1; i <= N; ++i)
200         tim[i] = map[++tot] = nextInt();
201
202     for (int i = 1; i < N; ++i)
203         addEdge(nextInt(), nextInt());
204
205     for (int i = 1; i <= M; ++i)
206     {
207         opt[i] = nextInt();
208         opx[i] = nextInt();
209         opy[i] = nextInt();
210
211         if (!opt[i])
212             map[++tot] = opy[i];
213     }
214
215     std::sort(map + 1, map + tot + 1);
216
217     tot = std::unique(map + 1, map + tot + 1) - map - 1;
218
219     for (int i = 1; i <= N; ++i)
220         tim[i] = std::lower_bound(map + 1, map + tot + 1, tim[i]) - map;
221
222     for (int i = 1; i <= M; ++i)if (!opt[i])
223         opy[i] = std::lower_bound(map + 1, map + tot + 1, opy[i]) - map;
224
225     preworkDFS(1, 0); buildDFS(1, 0);
226
227     for (int i = 1; i <= M; ++i)
228         if (!opt[i])
229         {
230             int x = opx[i];
231             int y = opy[i];
232
233             modify(arv[x], tim[x], -1);
234             modify(lev[x], tim[x], +1);
235
236             tim[x] = y;
237
238             modify(arv[x], tim[x], +1);
239             modify(lev[x], tim[x], -1);
240         }
241         else
242         {
243             clear();
244
245             int x = opx[i];
246             int y = opy[i];
247             int t = lca(x, y);
248
249             addQuery(x);
250             addQuery(y);
251             subQuery(t);
252             subQuery(fa[t][0]);
253
254             int ans = query(1, tot, opt[i]);
255
256             if (ans == -1)
257                 puts("invalid request!");
258             else
259                 printf("%d\n", map[ans]);
260         }
261 }

@Author: YouSiki

时间: 2024-10-06 22:32:54

BZOJ 1146: [CTSC2008]网络管理Network的相关文章

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(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

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

【BZOJ 1146】网络管理Network

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

【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条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机

【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

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

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

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

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