P4175 [CTSC2008]网络管理 树剖+树套树
$ \color{#0066ff}{ 题目描述 }$
M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门。为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络。该网络的结构由N个路由器和N-1条高速光缆组成。每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络。该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信。 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略。但是由于路由器老化,在这些路由器上进行数据交换会带来很大的延迟。而两个路由器之间的通信延迟时间则与这两个路由器通信路径上所有路由器中最大的交换延迟时间有关。作为M公司网络部门的一名实习员工,现在要求你编写一个简单的程序来监视公司的网络状况。该程序能够随时更新网络状况的变化信息(路由器数据交换延迟时间的变化),并且根据询问给出两个路由器通信路径上延迟第k大的路由器的延迟时间。
【任务】 你的程序从输入文件中读入N个路由器和N-1条光缆的连接信息,每个路由器初始的数据交换延迟时间Ti,以及Q条询问(或状态改变)的信息。并依次处理这Q条询问信息,它们可能是:
- 由于更新了设备,或者设备出现新的故障,使得某个路由器的数据交换延迟时间发生了变化。
- 查询某两个路由器a和b之间的路径上延迟第k大的路由器的延迟时间。
\(\color{#0066ff}{输入格式}\)
第一行为两个整数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,此时路径上只有一个路由器。
\(\color{#0066ff}{输出格式}\)
对于每一个第二种询问(k>0),输出一行。包含一个整数为相应的延迟时间。如果路径上的路由器不足k个,则输出信息“invalid request!”(全部小写不包含引号,两个单词之间有一个空格)。
\(\color{#0066ff}{输入样例}\)
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
\(\color{#0066ff}{输出样例}\)
3
2
2
invalid request!
\(\color{#0066ff}{数据范围与提示}\)
测试数据满足N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于\(10^8\)。对于所有询问满足0<=K<=N 。
\(\color{#0066ff}{题解}\)
单点修改,树链查询。。。树剖
查询第k大?数据范围80000? 树套树!
直接把树剖的线段树改成线段树套平衡树,二分找第k大,复杂度\(O(qlog^4n)\)能卡过!
注意查的是第k大不是第k小!!!
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
LL read() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
template<class T> bool chkmax(T &a, const T &b) { return a < b? a = b, 1 : 0; }
template<class T> bool chkmin(T &a, const T &b) { return b < a? a = b, 1 : 0; }
const int maxn = 1e5 + 10;
int dfn[maxn], nfd[maxn], top[maxn], son[maxn];
int siz[maxn], fa[maxn], dep[maxn], cnt, val[maxn];
struct Splay {
protected:
struct node {
node *ch[2], *fa;
int siz, val;
node(int siz = 0, int val = 0): siz(siz), val(val) { fa = ch[0] = ch[1] = NULL; }
void upd() { siz = (ch[0]? ch[0]->siz : 0) + (ch[1]? ch[1]->siz : 0) + 1; }
bool isr() { return this == fa->ch[1]; }
int rk() { return ch[0]? ch[0]->siz + 1 : 1; }
}*root;
void rot(node *x) {
node *y = x->fa, *z = y->fa;
bool k = x->isr(); node *w = x->ch[!k];
if(y != root) z->ch[y->isr()] = x;
else root = x;
(x->ch[!k] = y)->ch[k] = w;
(y->fa = x)->fa = z;
if(w) w->fa = y;
y->upd(), x->upd();
}
void splay(node *o) {
while(o != root) {
if(o->fa != root) rot(o->isr() ^ o->fa->isr()? o : o->fa);
rot(o);
}
}
node *merge(node *fa, node *x, node *y) {
if(x) x->fa = fa;
if(y) y->fa = fa;
if(!x || !y) return x? x : y;
if(rand() & 1) return x->ch[1] = merge(x, x->ch[1], y), x->upd(), x;
else return y->ch[0] = merge(y, x, y->ch[0]), y->upd(), y;
}
public:
Splay() { root = NULL; }
void ins(int val) {
if(!root) return (void)(root = new node(1, val));
node *o = root, *fa = NULL;
while(o) fa = o, o = o->ch[val > o->val];
fa->ch[val > fa->val] = o = new node(1, val);
o->fa = fa, splay(o);
}
void del(int val) {
node *o = root;
while(o && o->val != val) o = o->ch[val > o->val];
if(!o) return;
splay(o);
root = merge(NULL, o->ch[0], o->ch[1]);
}
int rnk(int val) {
int num = 0; node *o = root;
while(o) {
if(o->val < val) num += o->rk(), o = o->ch[1];
else o = o->ch[0];
}
return num;
}
};
struct Segment_Tree {
protected:
struct node {
node *ch[2];
int l, r;
Splay T;
node(int l = 0, int r = 0): l(l), r(r) { ch[0] = ch[1] = NULL; }
int mid() { return (l + r) >> 1; }
}*root;
void build(node *&o, int l, int r) {
o = new node(l, r);
for(int i = l; i <= r; i++) o->T.ins(val[nfd[i]]);
if(l == r) return;
build(o->ch[0], l, o->mid()); build(o->ch[1], o->mid() + 1, r);
}
int query(node *o, int l, int r, int val) {
if(l <= o->l && o->r <= r) return o->T.rnk(val);
int ans = 0;
if(l <= o->mid()) ans += query(o->ch[0], l, r, val);
if(r > o->mid()) ans += query(o->ch[1], l, r, val);
return ans;
}
public:
void change(int pos, int old, int now) {
node *o = root;
while(1) {
o->T.del(old), o->T.ins(now);
if(o->l == o->r) break;
if(pos <= o->mid()) o = o->ch[0];
else o = o->ch[1];
}
}
void init(int n) { build(root, 1, n); }
int query(int l, int r, int val) { return query(root, l, r, val); }
}T;
int n, m;
std::vector<int> G[maxn];
void dfs1(int x, int f) {
dep[x] = dep[fa[x] = f] + (siz[x] = 1);
for(auto to : G[x]) {
if(to == f) continue;
dfs1(to, x);
siz[x] += siz[to];
if(siz[to] > siz[son[x]]) son[x] = to;
}
}
void dfs2(int x, int t) {
top[nfd[dfn[x] = ++cnt] = x] = t;
if(son[x]) dfs2(son[x], t);
for(auto to : G[x]) if(!dfn[to]) dfs2(to, to);
}
void predoit() { dfs1(1, 0), dfs2(1, 1), T.init(n); }
void change(int x, int y) {
T.change(dfn[x], val[x], y);
val[x] = y;
}
int getans(int x, int y, int val) {
//printf("now is getans(%d -> %d, lower %d), ", x, y, val);
int ans = 0, fx = top[x], fy = top[y];
while(fx != fy) {
if(dep[fx] < dep[fy]) std::swap(fx, fy), std::swap(x, y);
ans += T.query(dfn[fx], dfn[x], val);
fx = top[x = fa[fx]];
}
if(dep[x] < dep[y]) std::swap(x, y);
ans += T.query(dfn[y], dfn[x], val);
//printf("ans = %d\n", ans);
return ans;
}
int getnum(int x, int y) {
int ans = 0, fx = top[x], fy = top[y];
while(fx != fy) {
if(dep[fx] < dep[fy]) std::swap(fx, fy), std::swap(x, y);
ans += (dfn[x] - dfn[fx] + 1);
fx = top[x = fa[fx]];
}
if(dep[x] < dep[y]) std::swap(x, y);
return ans + (dfn[x] - dfn[y] + 1);
}
void kthpath(int x, int y, int k) {
int num = getnum(x, y);
if(num < k) return (void)(puts("invalid request!"));
k = num - k + 1;
int l = 0, r = 1e8, ans = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(getans(x, y, mid) + 1 <= k) ans = mid, l = mid + 1;
else r = mid - 1;
}
printf("%d\n", ans);
}
int main() {
n = read(), m = read();
for(int i = 1; i <= n; i++) val[i] = read();
int x, y, k;
for(int i = 1; i < n; i++) {
x = read(), y = read();
G[x].push_back(y);
G[y].push_back(x);
}
predoit();
while(m --> 0) {
k = read(), x = read(), y = read();
if(!k) change(x, y);
else kthpath(x, y, k);
}
return 0;
}