BZOJ_1146_[CTSC2008]网络管理Network_主席树+树状数组

BZOJ_1146_[CTSC2008]网络管理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大的路由器的延迟时间。

注意N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。

对于所有询问满足0<=K<=N

Output

对于每一个第二种询问(k>0),输出一行。包含一个整数为相应的延迟时间。

如果路径上的路由器不足k个,则输出信息“invalidrequest!”

(全部小写不包含引号,两个单词之间有一个空格)。

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!


一般来说主席树维护树上信息的时候都是每个点维护点到根路径上的信息。

但这样还是在树上,修改不是很方便,于是把它放到序列上。

建立出栈入栈序,每个点在入栈的地方+1,出栈的位置-1。

前缀和就是这个点到根路径上的信息,转化成了序列问题。

然后这些操作都用树状数组做一下即可。

我这里写的有隐患,不能认为子树中最后出现的结点+1就是出栈的位置。

因为如果维护一些别的信息时,需要修改那个结点的信息,这样前一个点的出栈位置维护的信息就会也被修改。

并且空间也要开两倍。

(第k大)

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 80050
#define maxn 100000000
int n,m,head[N],to[N<<1],nxt[N<<1],val[N],dfn[N],cnt,out[N];
int fa[N],top[N],son[N],size[N],dep[N],tot,A[N],B[N],C[N],D[N];
int siz[N*250],ls[N*250],rs[N*250],root[N];
inline void add(int u,int v) {
	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void insert(int &y,int l,int r,int v,int c) {
	if(!y) y=++tot; siz[y]+=c;
	if(l==r) return ;
	int mid=(l+r)>>1;
	if(v<=mid) insert(ls[y],l,mid,v,c);
	else insert(rs[y],mid+1,r,v,c);
}
void dfs1(int x,int y) {
	int i; dep[x]=dep[y]+1; fa[x]=y; size[x]=1; dfn[x]=++dfn[0];
	for(i=dfn[x];i<=n;i+=i&(-i)) insert(root[i],0,maxn,val[x],1);
	for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
		dfs1(to[i],x); size[x]+=size[to[i]]; if(size[to[i]]>size[son[x]]) son[x]=to[i];
	}
	for(i=dfn[0]+1;i<=n;i+=i&(-i)) insert(root[i],0,maxn,val[x],-1);
	out[x]=dfn[0]+1;
}
void dfs2(int x,int t) {
	top[x]=t; if(son[x]) dfs2(son[x],t); int i;
	for(i=head[x];i;i=nxt[i]) if(to[i]!=fa[x]&&to[i]!=son[x]) dfs2(to[i],to[i]);
}
int lca(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]>dep[top[y]]) swap(x,y);
		y=fa[top[y]];
	}
	return dep[x]<dep[y]?x:y;
}
int query(int l,int r,int k) {
	if(l==r) return l;
	int mid=(l+r)>>1,i,sizls=0;
	for(i=1;i<=A[0];i++) sizls+=siz[ls[A[i]]];
	for(i=1;i<=B[0];i++) sizls+=siz[ls[B[i]]];
	for(i=1;i<=C[0];i++) sizls-=siz[ls[C[i]]];
	for(i=1;i<=D[0];i++) sizls-=siz[ls[D[i]]];
	if(k<=sizls) {
		for(i=1;i<=A[0];i++) A[i]=ls[A[i]];
		for(i=1;i<=B[0];i++) B[i]=ls[B[i]];
		for(i=1;i<=C[0];i++) C[i]=ls[C[i]];
		for(i=1;i<=D[0];i++) D[i]=ls[D[i]];
		return query(l,mid,k);
	}else {
		for(i=1;i<=A[0];i++) A[i]=rs[A[i]];
		for(i=1;i<=B[0];i++) B[i]=rs[B[i]];
		for(i=1;i<=C[0];i++) C[i]=rs[C[i]];
		for(i=1;i<=D[0];i++) D[i]=rs[D[i]];
		return query(mid+1,r,k-sizls);
	}
}
int main() {
	scanf("%d%d",&n,&m);
	int i,x,y,k;
	for(i=1;i<=n;i++) scanf("%d",&val[i]);
	for(i=1;i<n;i++) {
		scanf("%d%d",&x,&y); add(x,y); add(y,x);
	}
	dfs1(1,0); dfs2(1,1);
	while(m--) {
		scanf("%d%d%d",&k,&x,&y);
		if(!k) {
			for(i=dfn[x];i<=n;i+=i&(-i)) insert(root[i],0,maxn,val[x],-1);
			for(i=out[x];i<=n;i+=i&(-i)) insert(root[i],0,maxn,val[x],1);
			val[x]=y;
			for(i=dfn[x];i<=n;i+=i&(-i)) insert(root[i],0,maxn,val[x],1);
			for(i=out[x];i<=n;i+=i&(-i)) insert(root[i],0,maxn,val[x],-1);
		}else {
			A[0]=B[0]=C[0]=D[0]=0;
			int l=lca(x,y),len=dep[x]+dep[y]-dep[l]-dep[fa[l]];
			if(len<k) puts("invalid request!");
			else {
				k=len-k+1;
				for(i=dfn[x];i;i-=i&(-i)) A[++A[0]]=root[i];
				for(i=dfn[y];i;i-=i&(-i)) B[++B[0]]=root[i];
				for(i=dfn[l];i;i-=i&(-i)) C[++C[0]]=root[i];
				if(fa[l]) for(i=dfn[fa[l]];i;i-=i&(-i)) D[++D[0]]=root[i];
				printf("%d\n",query(0,maxn,k));
			}
		}
	}
}
/*
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
*/

原文地址:https://www.cnblogs.com/suika/p/8967719.html

时间: 2024-10-11 05:44:31

BZOJ_1146_[CTSC2008]网络管理Network_主席树+树状数组的相关文章

[CTSC2008]网络管理(整体二分+树剖+树状数组)

一道经典的带修改树链第 \(k\) 大的问题. 我只想出三个 \(\log\) 的解法... 整体二分+树剖+树状数组. 那不是暴力随便踩的吗??? 不过跑得挺快的. \(Code\ Below:\) // luogu-judger-enable-o2 #include <bits/stdc++.h> #define lowbit(x) ((x)&(-(x))) using namespace std; const int maxn=80000+10; const int lim=1e

线段树&amp;数状数组

线段树 单点修改,区间查询 #include<bits/stdc++.h> using namespace std; int n,q; long long num[1000010]; struct tree { int l,r; long long sum,max; }t[4000010]; void BuildTree(int,int,int); void Update(int,int,int,int,long long); long long Query(int,int,int,int,i

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

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

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

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

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

题目描述 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条高速光缆组成. 每个部门都有一个专属的路由器,

【poj1901-求区间第k大值(带修改)】树状数组套主席树

901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7025  Solved: 2925[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]

hdu 4605 Magic Ball Game (在线主席树/离线树状数组)

hdu 4605 题意: 有一颗树,根节点为1,每一个节点要么有两个子节点,要么没有,每个节点都有一个权值wi .然后,有一个球,附带值x . 球到达某个节点上,如果x==wi,那么球停在这个节点上 .当然,这个点是叶子节点也会停止 . 如果x<wi,那么有1/2的概率走向左子树,有1/2的概率走向右子树 . 如果x>wi,那么有1/8的概率走向左子树,有7/8的概率走向右子树 . 问球经过v节点的概率 .(停在v节点也算) 解法: 在线的话每一个节点建一棵根节点到该节点的线段树,离线的话就先

hdu_5788_Level Up(树状数组+主席树)

题目链接:hdu_5788_Level Up 题意: 有一棵树,n个节点,每个节点有个能力值A[i],mid[i],mid的值为第i节点的子树的中位数(包括本身),现在让你将其中的一个节点的A值改为1e5,问所有的mid的和最大问多少. 题解: 我们可以知道,如果改变其中一个的A[i],如果A[i]是比他父亲节点的mid小,那么他父亲的此时的中位数就会向后移一位 比如 1 2 3 4 5,第3个点是第2个点的父亲,如果改变了第二个点的A值,那么此时变成了1 3 4 5 1e5,第二个点的父亲的m