BZOJ 1146: [CTSC2008]网络管理Network 树链剖分 树状数组套主席树/线段树套平衡树

1146: [CTSC2008]网络管理Network

Time Limit: 50 Sec  Memory Limit: 256 MB
Submit: 3826  Solved: 1123
[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!

这个题。。。

树链剖分之后再上线段树套平衡树的做法应该很好想

树套树和BZOJ 3196: Tyvj 1730 二逼平衡树 树套树一模一样


之后,同时有一种做法广为流传

树上树状数组套主席树


感觉第一种做法的功效只能是锻炼代码力

第二种思路要更好,代码力锻炼也还可以 所以选第二种


讲一下题解:

(感觉其他博客讲的雾比较大,决定好好写一写)


要用到dfs序

先考虑不带修改

对于每个节点,维护其到root的主席树(对于节点x记为tr(x))

所以(u,v)可以由tr(u)+tr(v)-tr(lca)-tr(fa(lca))搞出来

这样就完美的解决了问题


那么我们再来看带修改的

那么我们就需要把树转换成线性序列来做

我们考虑对于一个节点权值修改

那么他会影响他的整个子树

一颗子树的dfs序一定在一个区间内

所以就可以搞了

先正常把主席树都搞出来

再新开n个节点,用树状数组套上

用差分的思想 tr(dfn[u])++,tr(dfn[u]+size[u])--

查询的时候合到一起就好了


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar('0'+x%10);}

const int N=80100;

int a[N],h[N<<1],n,Q,m;

int ecnt,last[N];
struct EDGE{int to,nt;}e[N<<1];
inline void add(int u,int v)
{e[++ecnt]=(EDGE){v,last[u]};last[u]=ecnt;}

struct question{int k,u,v;}q[N];

int fa[N][18],size[N],d[N],dfn[N],pos[N],dfncnt;

void dfs(int u)
{
	size[u]=1;dfn[u]=++dfncnt;pos[dfn[u]]=u;
	register int i;
	for(i=last[u];i;i=e[i].nt)
	{
		if(e[i].to==fa[u][0])continue;
		d[e[i].to]=d[u]+1;fa[e[i].to][0]=u;dfs(e[i].to);size[u]+=size[e[i].to];
	}
}

inline int hsh(int x)
{
	register int l=1,r=m,mid;
	while(l<=r)
	{
		mid=(l+r)>>1;
		if(h[mid]==x)return mid;
		h[mid]>x?r=mid-1:l=mid+1;
	}
	return 0;
}


struct president_tree{int w,ls,rs;}tr[N<<7];

int root[N],bit[N],cnt;

void insert(int &k,int x,int l,int r,int aim,int val)
{
	k=++cnt;tr[k].w=tr[x].w+val;
	if(l==r)return ;int mid=(l+r)>>1;
	tr[k].ls=tr[x].ls;tr[k].rs=tr[x].rs;
	aim>mid?insert(tr[k].rs,tr[x].rs,mid+1,r,aim,val):insert(tr[k].ls,tr[x].ls,l,mid,aim,val);
}

void build(int u)
{
	insert(root[u],root[fa[u][0]],1,m,a[u],1);
	for(int i=last[u];i;i=e[i].nt)
	{
		if(e[i].to==fa[u][0])continue;
		build(e[i].to);
	}
}

void init()
{
	dfs(1);
	register int i,j,tmp=0;
	for(j=1;j<=17;++j)for(i=1;i<=n;++i)fa[i][j]=fa[fa[i][j-1]][j-1];
	sort(h+1,h+1+m);h[++tmp]=h[1];
	for(i=2;i<=m;++i)if(h[i]!=h[tmp])h[++tmp]=h[i];
	m=tmp;
	for(i=1;i<=n;++i)a[i]=hsh(a[i]);
	build(1);
}

inline int getlca(int u,int v)
{
	register int i,len;
	if(d[u]<d[v])swap(u,v);
	len=d[u]-d[v];
	for(i=0;(1<<i)<=len;++i)if(len&(1<<i))u=fa[u][i];
	if(u==v)return u;
	for(i=17;i>=0;i--)if(fa[u][i]^fa[v][i])u=fa[u][i],v=fa[v][i];
	return fa[u][0];
}

inline void modify(int x,int aim,int val)
{for(;x<=n;x+=(x&-x))insert(bit[x],bit[x],1,m,aim,val);}

int L[N],R[N],lf,rf;

inline int check()
{
	register int i,sum=0;
	for(i=1;i<=lf;++i)sum-=tr[L[i]].w;
	for(i=1;i<=rf;++i)sum+=tr[R[i]].w;
	return sum;
}

inline void query(int u,int v,int rk)
{
	register int i,lca,l=1,r=m,mid,sum;lf=0,rf=0;
	lca=getlca(u,v);
	L[++lf]=root[lca];L[++lf]=root[fa[lca][0]];
	R[++rf]=root[u];R[++rf]=root[v];
	for(i=dfn[u];i;i-=(i&-i))R[++rf]=bit[i];
	for(i=dfn[v];i;i-=(i&-i))R[++rf]=bit[i];
	for(i=dfn[lca];i;i-=(i&-i))L[++lf]=bit[i];
	for(i=dfn[fa[lca][0]];i;i-=(i&-i))L[++lf]=bit[i];
	if(check()<rk){puts("invalid request!");return ;}
	while(l<r)
	{
		mid=(l+r)>>1;sum=0;
		for(i=1;i<=lf;++i)sum-=tr[tr[L[i]].rs].w;
		for(i=1;i<=rf;++i)sum+=tr[tr[R[i]].rs].w;
		if(sum>=rk)
		{
			for(i=1;i<=lf;++i)L[i]=tr[L[i]].rs;
			for(i=1;i<=rf;++i)R[i]=tr[R[i]].rs;
			l=mid+1;
		}
		else 
		{
			for(i=1;i<=lf;++i)L[i]=tr[L[i]].ls;
			for(i=1;i<=rf;++i)R[i]=tr[R[i]].ls;
			rk-=sum;r=mid;
		}
	}
	print(h[l]);puts("");
}

void solve()
{
	register int i,u,val;
	for(i=1;i<=Q;++i)
	{
		if(q[i].k)query(q[i].u,q[i].v,q[i].k);
		else
		{
			u=q[i].u;val=q[i].v;
			modify(dfn[u],a[u],-1);modify(dfn[u]+size[u],a[u],1);
			a[u]=hsh(val);
			modify(dfn[u],a[u],1);modify(dfn[u]+size[u],a[u],-1);
		}	
	}
}

int main()
{
	n=read();Q=read();
	register int i,
	u,v;
	for(i=1;i<=n;++i)a[i]=read(),h[++m]=a[i];
	for(i=1;i<n;++i){u=read();v=read();add(u,v);add(v,u);}
	for(i=1;i<=Q;++i){q[i].k=read();q[i].u=read();q[i].v=read();if(!q[i].k)h[++m]=q[i].v;}
	init();solve();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值