bzoj1146[CTSC2008]网络管理Network 整体二分+树链剖分

1146: [CTSC2008]网络管理Network

Time Limit: 50 Sec   Memory Limit: 256 MB
Submit: 4034   Solved: 1217
[ 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

题目大意:树上路径第k大(单点修改)

直接想法应该是树链剖分+平衡树吧

当然如果维护从点到根的路径应该可以用二维线段树来搞。

不管怎么样都挺烦的。

所以这里介绍的是整体二分的做法。

其实也蛮裸的

就是外围二分个答案,里面用树剖套线段树就可以了。

当数据结构模板打打吧。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 88000;
const int M = 88000;
int read() {
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
	return x * f;
}
struct Ques {int l, r, x, id, opt;}q[M << 2], q1[M << 2], q2[M << 2];
int ans[M], vis[M << 2], last[N];
int t[N], f[N], deep[N], dson[N], siz[N], d[N], in[N], n, tot;
int pre[N], to[N << 1], nxt[N << 1], top;
void add(int u, int v) {to[++top] = v; nxt[top] = pre[u]; pre[u] = top;}
void adds(int u, int v) {add(u, v); add(v, u);} 

void update(int x,int add) {for(int i = x; i <= n; t[i] += add, i += -i&i) ;}
int query(int x) {int ret = 0; for(int i = x; i ; ret += t[i], i -= -i&i) ; return ret;}

void dfs1(int u, int fa) {
	f[u] = fa; deep[u] = deep[fa] + 1; dson[u] = 0; siz[u] = 1;
	for(int i = pre[u]; i; i = nxt[i])
	if(to[i] != fa) {
		dfs1(to[i], u);
		siz[u] += siz[to[i]];
		if(siz[dson[u]] < siz[to[i]]) dson[u] = to[i];
	}
}

void dfs2(int u, int chain) {
	d[u] = chain; in[u] = ++tot; if(!dson[u]) return;
	dfs2(dson[u], chain);
	for(int i = pre[u]; i; i = nxt[i])
	if(to[i] != f[u] && to[i] != dson[u])
		dfs2(to[i], to[i]);
}


int query(int u, int v) {
	int ret = 0;
	while(d[u] != d[v]) {
		if(deep[d[u]] < deep[d[v]]) swap(u, v);
		ret += query(in[u]) - query(in[d[u]] - 1);
		u = f[d[u]];
	}
	if(in[u] > in[v]) swap(u, v);
	ret += query(in[v]) - query(in[u] - 1);
	return ret;
}

void work(int L, int R, int l, int r) {
	if(l > r) return;
	if(L == R) {
		for(int i = l;i <= r; ++i)
		if(q[i].opt == 2) ans[q[i].id] = L;
		return;
	}
	int mid = L + R >> 1;
	for(int i = l;i <= r; ++i) {
		if(q[i].opt < 2) {
			if(q[i].x <= mid) update(in[q[i].l], q[i].opt);
			vis[i] = q[i].x > mid;
		}
		if(q[i].opt == 2) {
			int k = query(q[i].l, q[i].r);
			if(k < q[i].x) {
				q[i].x -= k;
				vis[i] = true;
			}
			else vis[i] = false;
		}
	}
	int cnt1 = 0, cnt2 = 0;
	for(int i = l;i <= r; ++i) {
		if(q[i].opt < 2 && q[i].x <= mid) update(in[q[i].l], -q[i].opt);
		if(!vis[i]) q1[cnt1++] = q[i];
		else q2[cnt2++] = q[i];
	}
	for(int i = 0;i < cnt1; ++i) q[l + i] = q1[i];
	for(int i = 0;i < cnt2; ++i) q[l + cnt1 + i] = q2[i];
	work(L, mid, l, l + cnt1 - 1); work(mid + 1, R, l + cnt1, r);
}

int main() {
	memset(ans, -1, sizeof(ans));
	n = read(); int m = read(), tail = 0;
	for(int i = 1;i <= n; ++i)
		q[++tail].opt = 1, q[tail].l = i, last[i] = q[tail].x = read();
	for(int i = 1;i < n; ++i) adds(read(), read());
	dfs1(1, 0); dfs2(1, 1); 
	for(int i = 1;i <= n; ++i) update(in[i], 1);
	for(int i = 1;i <= m; ++i) {
		int opt = read(), x = read(), y = read();
		if(!opt) {
			q[++tail].opt = -1; q[tail].l = x; q[tail].x = last[x];
			q[++tail].opt = 1; q[tail].l = x; q[tail].x = y; last[x] = y;
		}
		else {
			opt = query(x, y) - opt + 1; if(opt <= 0) {ans[i] = -2; continue;}
			q[++tail].opt = 2, q[tail].l = x, q[tail].r = y;
			q[tail].id = i; q[tail].x = opt;
		}
	}
	memset(t, 0, sizeof(t));
	work(0, 1e8, 1, tail);
	for(int i = 1;i <= m; ++i) 
	if(~ans[i]) {
		if(ans[i] != -2) printf("%d\n", ans[i]);
		else puts("invalid request!");
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值