luogu P4175 [CTSC2008]网络管理

跟風遠走 提交于 2020-01-17 16:15:45

Description

M 公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门。为了让分布在世界各地的 nn 个部门之间协同工作,公司搭建了一个连接整个公司的通信网络。

该网络的结构由 n 个路由器和 n−1 条高速光缆组成。每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络。该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信。

高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略。但是由于路由器老化,在这些路由器上进行数据交换会带来很大的延迟。而两个路由器之间的通信延迟时间则与这两个路由器通信路径上所有路由器中最大的交换延迟时间有关。

作为 M 公司网络部门的一名实习员工,现在要求你编写一个简单的程序来监视公司的网络状况。该程序能够随时更新网络状况的变化信息(路由器数据交换延迟时间的变化),并且根据询问给出两个路由器通信路径上延迟第 kk 大的路由器的延迟时间。

【任务】
你的程序从输入文件中读入 n 个路由器和 n−1 条光缆的连接信息,每个路由器初始的数据交换延迟时间tit_i
,以及 q 条询问(或状态改变)的信息。并依次处理这 q 条询问信息,它们可能是:

1、由于更新了设备,或者设备出现新的故障,使得某个路由器的数据交换延迟时间发生了变化。

2、查询某两个路由器 a 和 v 之间的路径上延迟第 k 大的路由器的延迟时间。\


Input

第一行为两个整数 n 和 q,分别表示路由器总数和询问的总数。

第二行有 n 个整数,第 i 个数表示编号为i的路由器初始的数据延迟时间 tit_i

紧接着 n−1 行,每行包含两个整数 x 和 y。表示有一条光缆连接路由器 x 和路由器 y。

紧接着是 q 行,每行三个整数 k,a,b。

如果 k=0,则表示路由器 aa 的状态发生了变化,它的数据交换延迟时间由 tat_a 变为 b。

如果 k>0,则表示询问 a 到 b 的路径上所经过的所有路由器(包括 a 和 b)中延迟第 k 大的路由器的延迟时间。注意 a 可以等于 b,此时路径上只有一个路由器。


Output

对于每一个第二种询问(即 k>0 ),输出一行。
包含一个整数为相应的延迟时间。如果路径上的路由器不足 k 个,则输出信息 invalid request! 。


Solution

O(nlog2nnlog^2n)做法:

思路简单,实现一般。

很直接地想到主席树维护dfs序搞k大,树链剖分求lca。
因为要修改,是一段前缀和的修改,所以要用树状数组套主席树。

然后就没有然后了。。。
就是注意一下代码的细节。

dfs序的修改保证子树连续,所以可以通过区间修改子树的值,而且不会影响到后面的点求值。
x-y的路径用树上差分算就行了,ans=v[x]+v[y]v[lca]v[f[lca]]ans=v[x]+v[y]-v[lca]-v[f[lca]]


Code

#include<bits/stdc++.h>
using namespace std;
int a[80010],b[160010],n,q,m;
int e[160010],nxt[160010],head[80010],cnt;
int top[80010],dep[80010],son[80010],fa[80010],siz[80010];
int tree[128*80010],ls[128*80010],rs[128*80010],sz;
int ln[80010],rn[80010],tot;
int rt[80010],crt[80010];
int A[160010],B[160010];
struct data{
	int k,x,y;
}qy[80010];
void add(int x,int y){
	cnt++;
	e[cnt]=y;
	nxt[cnt]=head[x];
	head[x]=cnt;
}
int find(int x){
	int l=1,r=m+1;
	while(l<r-1){
		int mid=(l+r)>>1;
		if(x>=b[mid]) l=mid;
		else r=mid;
	}
	return l;
}
void dfs1(int x,int f){
	fa[x]=f;
	siz[x]=1;
	for(int i=head[x];i;i=nxt[i]){
		int y=e[i];
		if(y==f) continue;
		dep[y]=dep[x]+1;
		dfs1(y,x);
		siz[x]+=siz[y];
		if(siz[y]>siz[son[x]])
		son[x]=y;
	}
}
void dfs2(int x,int tp){
	if(x==0) return;
	top[x]=tp;
	ln[x]=++tot;
	dfs2(son[x],tp);
	for(int i=head[x];i;i=nxt[i])
	if(top[e[i]]==0) dfs2(e[i],e[i]);
	rn[x]=tot;
}
int lca(int x,int y){
	while(top[x]!=top[y]){
		if(x==0) exit(0);
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	return x;
}
void ins(int &x,int l,int r,int d,int v){
	sz++;
	ls[sz]=ls[x];
	rs[sz]=rs[x];
	tree[sz]=tree[x]; 
	x=sz,tree[x]+=v;
	if(l==r) return;
	int mid=(l+r)>>1;
	if(d<=mid) ins(ls[x],l,mid,d,v);
	else ins(rs[x],mid+1,r,d,v);
}
void build(int x){
	rt[x]=rt[fa[x]];
	ins(rt[x],1,m,a[x],1);//从fa转移到x
	if(son[x]==0) return;
	build(son[x]);
	for(int i=head[x];i;i=nxt[i])
	if(e[i]!=fa[x]&&e[i]!=son[x])
	build(e[i]); 
}
int lowbit(int x){
	return x&-x;
}
void upt(int x,int d,int v){
	for(int i=x;i<=tot;i+=lowbit(i))
	ins(crt[i],1,m,d,v);
}
bool check(int k){
	long long sum=0;
	for(int i=1;i<=A[0];i++) sum+=tree[A[i]];
	for(int i=1;i<=B[0];i++) sum-=tree[B[i]];
	return sum>=k;
}
void query(int k,int x,int y){
	A[0]=B[0]=0;
	int f=lca(x,y);
	A[++A[0]]=rt[x],A[++A[0]]=rt[y];
	B[++B[0]]=rt[f],B[++B[0]]=rt[fa[f]];
	for(int i=ln[x];i;i-=lowbit(i)) A[++A[0]]=crt[i]; //因为dfs序子树连续才可以这样写
	for(int i=ln[y];i;i-=lowbit(i)) A[++A[0]]=crt[i];
	for(int i=ln[f];i;i-=lowbit(i)) B[++B[0]]=crt[i];
	for(int i=ln[fa[f]];i;i-=lowbit(i)) B[++B[0]]=crt[i];
	if(check(k)==0){
		printf("invalid request!\n");
		return;
	}
	int l=1,r=m;
	while(l<r){
		int mid=(l+r)>>1;
		long long sum=0;
		for(int i=1;i<=A[0];i++) sum+=tree[rs[A[i]]];
		for(int i=1;i<=B[0];i++) sum-=tree[rs[B[i]]];
		if(k>sum){
			for(int i=1;i<=A[0];i++) A[i]=ls[A[i]];
			for(int i=1;i<=B[0];i++) B[i]=ls[B[i]];
			k-=sum,r=mid;
		}
		else{
			for(int i=1;i<=A[0];i++) A[i]=rs[A[i]];
			for(int i=1;i<=B[0];i++) B[i]=rs[B[i]];
			l=mid+1;
		}
	}
	printf("%d\n",b[l]);
}
int main(){
	int k,x,y,t=0;
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[++t]=a[i];
	}
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	dfs1(1,0),dfs2(1,1);
	for(int i=1;i<=q;i++){
		scanf("%d%d%d",&qy[i].k,&qy[i].x,&qy[i].y);
		if(qy[i].k==0) b[++t]=qy[i].y;
	}
	sort(b+1,b+t+1);
	m=unique(b+1,b+t+1)-b-1;
	for(int i=1;i<=n;i++) 
	a[i]=find(a[i]);;
	build(1);
	for(int i=1;i<=q;i++){
		k=qy[i].k,x=qy[i].x,y=qy[i].y;
		if(k==0){
			upt(ln[x],a[x],-1);
			upt(rn[x]+1,a[x],1);//保证不影响后面的点
			a[x]=find(y);
			upt(ln[x],a[x],1);
			upt(rn[x]+1,a[x],-1);
		}
		else query(k,x,y);
	}
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!