【bzoj1146】 [CTSC2008]网络管理Network【树链剖分+树套树+二分 线段树套Treap】

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个,
则输出信息“invalid request!”(全部小写不包含引号,两个单词之间有一个空格)。

蒟弱写的第一篇blog,好兴奋!

思路:树链剖分+树套树。

首先树链剖分一下,接下来线段树套Treap,修改时就在线段树上走一下,删除原来的值并且插入新的值。查询时,二分答案,求mid的排名,逐渐向答案逼近。查询排名,就是求比这个数小的数的个数+1。为了效率不至于太低,我离散化了一下。细节详见代码。时间复杂度线段树一个log,Treap还有一个log,查询还有树剖1个log,二分1个log。因此修改是2个log,查询是4个log,总时间复杂度O(nlog^4n)。 码得好爽啊,260行代码居然没有调试,1A。但是。。。。。。这份代码跑得像shi一样慢,30s+。废话4个log能跑多快。

代码:

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
inline int rd()
{
	char ch=getchar();
	int ret=0,f=1;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		ret=ret*10+ch-'0';
		ch=getchar();
	}
	return ret*f;
}
const int N=80005;
int n,q,u,v,cnt=0,idx=0,tot=0,ans,a[N],hash[N*2],K[N],A[N],B[N],root[N*4];
int head[N],to[N*2],nxt[N*2],size[N],son[N],dep[N],fa[N],pos[N],top[N];
int mempool[N*20],key[N*20],rnd[N*20],siz[N*20],w[N*20],ch[N*20][2];
int ins,rmv;
int getid(int x)
{
	return lower_bound(hash+1,hash+hash[0]+1,x)-hash;
}
void adde(int u,int v)
{
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}
void dfs1(int u)
{
	size[u]=1;
	for(int v=head[u];v;v=nxt[v])
		if(to[v]!=fa[u])
		{
			fa[to[v]]=u;
			dep[to[v]]=dep[u]+1;
			dfs1(to[v]);
			size[u]+=size[to[v]];
			if(!son[u]||size[son[u]]<size[to[v]])
				son[u]=to[v];
		}
}
void dfs2(int u,int tp)
{
	pos[u]=++idx;
	top[u]=tp;
	if(son[u]) dfs2(son[u],tp);
	for(int v=head[u];v;v=nxt[v])
		if(to[v]!=fa[u]&&to[v]!=son[u])
			dfs2(to[v],to[v]);
}
void maintain(int k)
{
	siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+w[k];
}
void rturn(int &k)
{
	int t=ch[k][0];
	ch[k][0]=ch[t][1];
	ch[t][1]=k;
	siz[t]=siz[k];
	maintain(k);
	k=t;
}
void lturn(int &k)
{
	int t=ch[k][1];
	ch[k][1]=ch[t][0];
	ch[t][0]=k;
	siz[t]=siz[k];
	maintain(k);
	k=t;
}
void insert(int &k,int x)
{
	if(!k)
	{
		k=mempool[mempool[0]--];
		key[k]=x;
		rnd[k]=rand();
		siz[k]=w[k]=1;
		ch[k][0]=ch[k][1]=0;
		return;
	}
	siz[k]++;
	if(x==key[k]) w[k]++;
	else if(x<key[k])
	{
		insert(ch[k][0],x);
		if(rnd[ch[k][0]]<rnd[k]) rturn(k);
	}
	else
	{
		insert(ch[k][1],x);
		if(rnd[ch[k][1]]<rnd[k]) lturn(k);
	}
}
void remove(int &k,int x)
{
	if(x==key[k])
	{
		if(w[k]>1)
		{
			siz[k]--;
			w[k]--;
			return;
		}
		else if(ch[k][0]*ch[k][1]==0)
		{
			mempool[++mempool[0]]=k;
			if(!ch[k][0]) k=ch[k][1];
			else k=ch[k][0];
		}
		else
		{
			if(rnd[ch[k][0]]>rnd[ch[k][1]]) lturn(k);
			else rturn(k);
			remove(k,x);
		}
	}
	else
	{
		siz[k]--;
		if(x<key[k]) remove(ch[k][0],x);
		else remove(ch[k][1],x);
	}
}
void rnk(int k,int x)
{
	while(k)
	{
		if(x<=key[k]) k=ch[k][0];
		else
		{
			ans+=siz[ch[k][0]]+w[k];
			k=ch[k][1];
		}
	}
}
void build(int o,int l,int r,int k)
{
	insert(root[o],ins);
	if(l==r) return;
	int mid=(l+r)/2;
	if(k<=mid) build(o*2,l,mid,k);
	else build(o*2+1,mid+1,r,k);
}
void change(int o,int l,int r,int k)
{
	remove(root[o],rmv);
	insert(root[o],ins);
	if(l==r) return;
	int mid=(l+r)/2;
	if(k<=mid) change(o*2,l,mid,k);
	else change(o*2+1,mid+1,r,k);
}
void query(int o,int l,int r,int L,int R,int k)
{
	if(L<=l&&R>=r)
	{
		rnk(root[o],k);
		return;
	}
	int mid=(l+r)/2;
	if(L<=mid) query(o*2,l,mid,L,R,k);
	if(R>mid) query(o*2+1,mid+1,r,L,R,k);
}
int LCA(int u,int v)
{
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		u=fa[top[u]];
	}
	if(dep[u]>dep[v]) swap(u,v);
	return u;
}
void solvequery(int u,int v,int k)
{
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		query(1,1,n,pos[top[u]],pos[u],k);
		u=fa[top[u]];
	}
	if(dep[u]>dep[v]) swap(u,v);
	query(1,1,n,pos[u],pos[v],k);
}
int main()
{
	for(int i=1600000;i>=1;i--) mempool[++mempool[0]]=i;
	n=rd(),q=rd();
	for(int i=1;i<=n;i++)
		hash[++hash[0]]=a[i]=rd();
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		adde(u,v);
		adde(v,u);
	}
	dfs1(1);
	dfs2(1,1);
	for(int i=1;i<=q;i++)
	{
		K[i]=rd(),A[i]=rd(),B[i]=rd();
		if(!K[i]) hash[++hash[0]]=B[i];
	}
	sort(hash+1,hash+hash[0]+1);
	hash[0]=unique(hash+1,hash+hash[0]+1)-hash-1;
	for(int i=1;i<=n;i++)
	{
		ins=getid(a[i]);
		build(1,1,n,pos[i]);
	}
	for(int i=1;i<=q;i++)
	{
		if(!K[i])
		{
			ins=getid(B[i]);
			rmv=getid(a[A[i]]);
			change(1,1,n,pos[A[i]]);
			a[A[i]]=B[i];
		}
		else
		{
			int lca=LCA(A[i],B[i]),siz=dep[A[i]]+dep[B[i]]-dep[lca]*2+1;
			if(siz<K[i])
			{
				puts("invalid request!");
				continue;
			}
			K[i]=siz-K[i]+1;
			int l=1,r=hash[0],tmp;
			while(l<=r)
			{
				int mid=(l+r)/2;
				ans=1;
				solvequery(A[i],B[i],mid);
				if(ans<=K[i])
				{
					l=mid+1;
					tmp=mid;
				}
				else r=mid-1;
			}
			printf("%d\n",hash[tmp]);
		}
	}
	return 0;
}



评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值