bzoj 1146: [CTSC2008]网络管理Network

本文介绍了一种用于解决网络路径查询问题的高效算法。该算法能在路由器数据交换延迟时间发生变动的情况下,快速更新网络状态,并能准确找出任意两点间通信路径上延迟第k大的路由器的延迟时间。

摘要生成于 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大的路由器的延迟时间。注意a可以等于b,此时路径上只有一个路由器。

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!

HINT

10% 测试数据满足N<=8000,Q<=3000,

40% 测试数据满足所有询问中1<=K<=5 。即路由器的延迟时间不会发生变化。

100% 测试数据满足N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。对于所有询问满足0<=K<=N 。


第300题一定要是一题看起来比较厉害的题
——————————————————————————————————————————————
对于一条路径[u,v],我们可以看成[1,u]+[1,v]-[1,lca(u,v)]+[1,fa[lca(u,v)]]
维护dfs序即可维护上述式子
那么如果没有修改操作。这就是一个主席树裸题了。
那么如果有修改操作呢?树状数组维护前缀和即可!
然后就和序列上求区间k大一样了
P.S 一开始我把dfs序值初始化也丢进树状数组结果各种MLE。其实树状数组只要维护后面的修改操作就可以了
#include<cstdio>
#include<algorithm>
using namespace std;
struct line
{
     int s,t;
     int next;
}a[160001];
int head[80001];
int edge;
inline void add(int s,int t)
{
	 a[edge].next=head[s];
	 head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
}
struct tree
{
	 //int l,r;
     int ll,rr;
     int s;
}tr[10000001];
int tot;
inline void build(int l,int r)
{
     int p=tot;
//     tr[p].l=l;
//     tr[p].r=r;
     if(l!=r)
     {
          int mid=(l+r)/2;
          tot++;
          tr[p].ll=tot;
          build(l,mid);
          tot++;
          tr[p].rr=tot;
          build(mid+1,r);
          tr[p].s=tr[tr[p].ll].s+tr[tr[p].rr].s;
     }
}
inline int inc(int p,int l,int r,int lx,int rx,int x)
{
//	 if(p==0)
//	      return 0;
     if(l==lx&&rx==r)
     {
     	  tot++;
//     	  tr[tot].l=tr[p].l;
  //   	  tr[tot].r=tr[p].r;
          tr[tot].s=tr[p].s+x;
          return tot;
     }
     else
     {
          int mid=(lx+rx)/2;
          tot++;
          int pp=tot;
       //   tr[pp].l=tr[p].l;
     //     tr[pp].r=tr[p].r;
          if(l<=mid)
          {
               tr[pp].ll=inc(tr[p].ll,l,r,lx,mid,x);
               tr[pp].rr=tr[p].rr;
          }
          else if(r>mid)
          {
               tr[pp].ll=tr[p].ll;
               tr[pp].rr=inc(tr[p].rr,l,r,mid+1,rx,x);
          }
          tr[pp].s=tr[tr[pp].ll].s+tr[tr[pp].rr].s;
          return pp;
     }
}
int N1,N2,N3,N4;
int L1[801],L2[801],L3[801],L4[801];
inline int find(int l,int r,int k)
{
	 if(l==r)
               return l;
	 else
	 {
          int tmp1=0,tmp2=0,tmp3=0,tmp4=0;
          int i;
          for(i=1;i<=N1;i++)
               tmp1+=tr[tr[L1[i]].ll].s;
          for(i=1;i<=N2;i++)
               tmp2+=tr[tr[L2[i]].ll].s;
          for(i=1;i<=N3;i++)
               tmp3+=tr[tr[L3[i]].ll].s;
          for(i=1;i<=N4;i++)
               tmp4+=tr[tr[L4[i]].ll].s;
          int tmp=tmp1+tmp2-tmp3-tmp4;
          int mid=(l+r)/2;
          if(tmp>=k)
          {
               for(i=1;i<=N1;i++)
                    L1[i]=tr[L1[i]].ll;
               for(i=1;i<=N2;i++)
                    L2[i]=tr[L2[i]].ll;
               for(i=1;i<=N3;i++)
                    L3[i]=tr[L3[i]].ll;
               for(i=1;i<=N4;i++)
                    L4[i]=tr[L4[i]].ll;
               return find(l,mid,k);
          }
          else
          {
               for(i=1;i<=N1;i++)
                    L1[i]=tr[L1[i]].rr;
               for(i=1;i<=N2;i++)
                    L2[i]=tr[L2[i]].rr;
               for(i=1;i<=N3;i++)
                    L3[i]=tr[L3[i]].rr;
               for(i=1;i<=N4;i++)
                    L4[i]=tr[L4[i]].rr;
               return find(mid+1,r,k-tmp);
          }
     }
}
int tx;
int w[160001],ld[80001],rd[80001];
int dep[80001],fa[80001];
int anc[80001][22];
int ax[80001][22];
bool v[80001];
inline void dfs(int d)
{
	 tx++;
	 w[tx]=d;
	 ld[d]=tx;
	 v[d]=true;
     int i,j;
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
          if(!v[t])
          {
          	   dep[t]=dep[d]+1;
          	   fa[t]=d;
          	   anc[t][0]=d;
          	   ax[t][0]=1;
          	   for(j=1;j<=20;j++)
          	   {
          	        anc[t][j]=anc[anc[t][j-1]][j-1];
          	        ax[t][j]=ax[anc[t][j-1]][j-1]+ax[t][j-1];
          	   }
               dfs(t);
          }
     }
     tx++;
     w[tx]=-d;
     rd[d]=tx;
}
int sux;
inline int swim(int x,int y)
{
     int i=20;
     while(dep[x]>dep[y])
     {
          while(dep[anc[x][i]]<=dep[y]&&i>0)
               i--;
          sux+=ax[x][i];
          x=anc[x][i];
     }
     return x;
}
inline int lca(int x,int y)
{
     if(dep[x]<dep[y])
     {
          int t=x;
          x=y;
          y=t;
     }
     x=swim(x,y);
     int i=20;
     while(x!=y)
     {
          while(anc[x][i]==anc[y][i]&&i>0)
               i--;
          sux+=ax[x][i];
          x=anc[x][i];
          sux+=ax[y][i];
          y=anc[y][i];
     }
     sux++;
     return x;
}
inline int lowbit(int x)
{
     return x&(-x);
}
int px;
int pl[200001];
int plx[200001];
inline void inc_bit(int l,int tt,int x)
{
     int i;
     for(i=l;i<=tx;i+=lowbit(i))
     {
          int txt=plx[i];
          plx[i]=tot+1;
          if(txt==0)
               txt=plx[0];
          inc(txt,tt,tt,1,px,x);
     }
}
inline int ask_bit(int u,int v,int k)
{
	 sux=0;
     int lc=lca(u,v);
     int i;
     N1=1;
     N2=1;
     N3=1;
     N4=1;
     L1[N1]=pl[ld[u]];
     for(i=ld[u];i>=1;i-=lowbit(i))
     {
          N1++;
          L1[N1]=plx[i];
     }
     L2[N2]=pl[ld[v]];
     for(i=ld[v];i>=1;i-=lowbit(i))
     {
          N2++;
          L2[N2]=plx[i];
     }
     L3[N3]=pl[ld[lc]];
     for(i=ld[lc];i>=1;i-=lowbit(i))
     {
          N3++;
          L3[N3]=plx[i];
     }
     L4[N4]=pl[ld[fa[lc]]];
     for(i=ld[fa[lc]];i>=1;i-=lowbit(i))
     {
          N4++;
          L4[N4]=plx[i];
     }
     //printf("%d\n",sux);
     if(sux>=k)
          return find(1,px,sux+1-k);
     else
          return -1;
}
int b[100001];
struct number
{
     int x,p;
     bool operator <(number y) const
     {
          return x<y.x;
     }
}c[200001];
struct askx
{
     int k,u,v;
     int p;
}ask[80001];
int f[200001];
int fx[200001];
int main()
{
//	 freopen("network.in","r",stdin);
//	 freopen("network.out","w",stdout);
	 int n,m;
	 scanf("%d%d",&n,&m);
	 int i;
	 int pp=0;
	 for(i=1;i<=n;i++)
	 {
	      scanf("%d",&b[i]);
	      pp++;
	      c[pp].p=pp;
	      c[pp].x=b[i];
	 }
	 int s,t;
	 for(i=1;i<=n-1;i++)
	 {
	      scanf("%d%d",&s,&t);
	      edge++;
	      add(s,t);
	      edge++;
	      add(t,s);
	 }
	 for(i=1;i<=m;i++)
	 {
	      scanf("%d%d%d",&ask[i].k,&ask[i].u,&ask[i].v);
	      if(ask[i].k==0)
	      {
	           pp++;
	           c[pp].p=pp;
	           ask[i].p=pp;
	           c[pp].x=ask[i].v;
	      }
	 }
	 sort(c+1,c+1+pp);
	 px++;
	 f[px]=c[1].x;
	 fx[c[1].p]=px;
	 for(i=2;i<=pp;i++)
	 {
	      if(c[i].x!=c[i-1].x)
	      {
	           px++;
	           f[px]=c[i].x;
	      }
	      fx[c[i].p]=px;
	 }
	 tot++;
	 pl[0]=tot;
	 build(1,px);
	 for(i=0;i<=20;i++)
	      anc[1][i]=1;
	 dep[1]=1;
	 dfs(1);
	// printf("*\n");
/*	 for(i=1;i<=tx;i++)
	 {
	      if(w[i]>0)
	           inc_bit(i,fx[w[i]],1);
	      else
	           inc_bit(i,fx[-w[i]],-1);
	  //    printf("%d %d\n",i,tot);
	 }*/
	 //printf("%d\n",tot);
     for(i=1;i<=tx;i++)
	 {
	 	  if(w[i]>0)
	 	  {
	 	       int txt=pl[i-1];
	 	       pl[i]=tot+1;
	 	       inc(txt,fx[w[i]],fx[w[i]],1,px,1);
	 	  }
	 	  else
	 	  {
	 	       int txt=pl[i-1];
	 	       pl[i]=tot+1;
	 	       inc(txt,fx[-w[i]],fx[-w[i]],1,px,-1);
	 	  }
	  //    printf("%d %d\n",i,tot);
	 }
	 for(i=1;i<=m;i++)
	 {
	      if(ask[i].k==0)
	      {
	           inc_bit(ld[ask[i].u],fx[ask[i].u],-1);
	           inc_bit(ld[ask[i].u],fx[ask[i].p],1);
	           inc_bit(rd[ask[i].u],fx[ask[i].u],1);
	           inc_bit(rd[ask[i].u],fx[ask[i].p],-1);
	           fx[ask[i].u]=fx[ask[i].p];
	      }
	      else
	      {
	           int sx=ask_bit(ask[i].u,ask[i].v,ask[i].k);
	           if(sx!=-1)
	      	        printf("%d\n",f[sx]);
	      	   else
	      	        printf("invalid request!\n");
	      }
	    //  printf("%d %d\n",i,tot);
	 }
     return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值