【bzoj1146】【CTSC2008】【网络管理】【树链剖分+线段树套平衡树】

本文介绍了一种解决特定网络监控问题的算法实现,利用树链剖分结合线段树套Treap的技术,实现了高效的路由器状态更新与路径延迟查询。适用于大规模网络监控场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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!

题解:

本题做法有很多种.我采用的是树链剖分+线段树套treap的方法。

就是在经典的树套树问题上加了一个链剖.

第k大不好处理可以变成第k小.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define N 80010
#define inf 100000000
using namespace std;
int n,q,a[N],cnt,next[N<<1],point[N],x,y,kind,ans,rk;
int sz,ls[N*60],rs[N*60],root[N<<2];
int bl[N],pos[N],fa[N][20],deep[N],size[N],num;
struct treap{int rd,w,v,s; }tr[N*60];
struct edge{int st,en;}e[N<<1];
int read(){
  int x(0);
  char ch=getchar();
  while (ch<'0'||ch>'9') ch=getchar();
  while (ch>='0'&&ch<='9')  x=x*10+ch-'0',ch=getchar();
  return x;
}
void add(int x,int y){
  next[++cnt]=point[x];point[x]=cnt;
  e[cnt].en=y;
}
void dfs(int x){
  size[x]=1;
  for (int i=1;(1<<i)<=deep[x];i++) 
    fa[x][i]=fa[fa[x][i-1]][i-1];
  for (int i=point[x];i;i=next[i])
    if (e[i].en!=fa[x][0]){
       fa[e[i].en][0]=x;deep[e[i].en]=deep[x]+1;
	   dfs(e[i].en);size[x]+=size[e[i].en];
    }
}
void dfs2(int x,int c){
  pos[x]=++num;bl[x]=c;
  int k(0);
  for (int i=point[x];i;i=next[i])
    if (e[i].en!=fa[x][0]&&size[e[i].en]>size[k]) k=e[i].en;
  if (!k) return;dfs2(k,c);
  for (int i=point[x];i;i=next[i])
    if (e[i].en!=fa[x][0]&&e[i].en!=k)
      dfs2(e[i].en,e[i].en);
} 
int lca(int x,int y){
  if (deep[x]<deep[y]) swap(x,y);
  int t=deep[x]-deep[y];
  for (int i=0;i<=18;i++) if (t&(1<<i)) x=fa[x][i];
  for (int i=18;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
  if (x==y) return x;else return fa[x][0];
}
void update(int k){
  tr[k].s=tr[ls[k]].s+tr[rs[k]].s+tr[k].w;
}
void lturn(int &k){
  int t=rs[k];rs[k]=ls[rs[k]];ls[t]=k;
  update(k);update(t);k=t;
}
void rturn(int &k){
  int t=ls[k];ls[k]=rs[ls[k]];rs[t]=k;
  update(k);update(t);k=t;
}
void insert(int &k,int v){
  if (!k){k=++sz;tr[k].s=tr[k].w=1;tr[k].v=v;tr[k].rd=rand();return;}
  if (tr[k].v==v) tr[k].w++;
  else if (v<tr[k].v){insert(ls[k],v);if (tr[ls[k]].rd<tr[k].rd) rturn(k);}
  else{insert(rs[k],v);if (tr[rs[k]].rd<tr[k].rd) lturn(k);}
  update(k);
}
void del(int &k,int v){
  if (!k) return;
  if (tr[k].v==v){
    if (tr[k].w>1) tr[k].w--;
    else{
      if (ls[k]*rs[k]==0) k=ls[k]+rs[k];
      else if (tr[ls[k]].rd<tr[k].rd){rturn(k);del(k,v);}
      else {lturn(k);del(k,v);}
    }
  }
  else if (v<tr[k].v) del(ls[k],v);
  else del(rs[k],v);
  update(k);
}
void build(int k,int l,int r,int x,int v){
  insert(root[k],v);
  int mid=(l+r)>>1;
  if (l==r) return;
  if (x<=mid) build(k<<1,l,mid,x,v);
  else build(k<<1|1,mid+1,r,x,v);
}
void change(int k,int l,int r,int x,int pre,int now){
  del(root[k],pre);insert(root[k],now);
  int mid=(l+r)>>1;
  if (l==r) return;
  if (x<=mid) change(k<<1,l,mid,x,pre,now);
  else change(k<<1|1,mid+1,r,x,pre,now);
}
void ask(int k,int v){
  if (!k) return;
  if (tr[k].v==v) {ans+=tr[ls[k]].s;return;}
  else if (v<tr[k].v) ask(ls[k],v);
  else{ans+=tr[ls[k]].s+tr[k].w;ask(rs[k],v);}
}
void query(int k,int l,int r,int ll,int rr,int v){
  if (l==ll&&r==rr){ask(root[k],v);return;}
  int mid=(l+r)>>1;
  if (rr<=mid) query(k<<1,l,mid,ll,rr,v);
  else if (mid<ll) query(k<<1|1,mid+1,r,ll,rr,v);
  else{
    query(k<<1,l,mid,ll,mid,v);
    query(k<<1|1,mid+1,r,mid+1,rr,v);
  }
}
void getrk(int x,int y,int v){
  while (bl[x]!=bl[y]){
  	query(1,1,n,pos[bl[x]],pos[x],v);
  	x=bl[x];x=fa[x][0];
  }
  query(1,1,n,pos[y],pos[x],v);
}
void getans(){
  int f=lca(x,y),sum=deep[x]+deep[y]-2*deep[f]+1;
  if (rk>sum){puts("invalid request!");return;}
  int l=0,r=inf,val;rk=sum-rk+1;
  while (l<=r){
    int mid=(l+r)>>1;
    ans=1;
	getrk(y,f,mid);getrk(x,f,mid);
	if (a[f]<mid) ans--;
    if (ans<=rk){l=mid+1;val=mid;}
    else r=mid-1;
  }  
  printf("%d\n",val);
}
int main(){
  n=read();q=read();
  for (int i=1;i<=n;i++) a[i]=read();
  for (int i=1;i<=n-1;i++){
    x=read();y=read();
    add(x,y);add(y,x);
  }	
  dfs(1);dfs2(1,1);
  for (int i=1;i<=n;i++) build(1,1,n,pos[i],a[i]);
  for (int i=1;i<=q;i++){
    kind=read();
    if (kind==0){
       x=read();y=read();
       change(1,1,n,pos[x],a[x],y);
       a[x]=y;
    }
    else{
      x=read();y=read();rk=kind;
      getans();
    }
  }
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值