【主席树】BZOJ 1146 network网络管理

BZOJ 1146 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大的路由器的延迟时间。注意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 。


Solution

主要是主席树+树状数组
在dfs序上差分,每次答案是t[l]+t[r]-t[lca(l,r)]-t[fa[lca(l,r)]].
然后还有lca
空间卡的略死。。

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;

#define maxn 80001

struct ope{
    int v,id;
    bool flg;
}op[maxn*2];

struct ASK{
    int k,x,y;
}ask[maxn];

int last[maxn],fir[maxn],lst[maxn],dep[maxn],root[2*maxn],sroot[2*maxn];

int v[maxn],L[maxn],R[maxn],LL[maxn],FLL[maxn],fa[18][maxn],seq[maxn*2];

int m1,m2,m3,m4,top,tot,su,size,n;

struct edge{
    int to,last;
}e[maxn*2];

struct TREE{
    int l,r,v;
}t[maxn*115];

void add(int u,int v)
{
    e[++tot].to=v,e[tot].last=last[u];last[u]=tot;
    e[++tot].to=u,e[tot].last=last[v],last[v]=tot;
}

bool cmp(const ope A,const ope B)
{
    return A.v<B.v;
}

void pre()
{
    for(int i=1;(1<<i)<=n;i++)
        for(int j=1;j<=n;j++)
            if(fa[i-1][j])fa[i][j]=fa[i-1][fa[i-1][j]];
}

void dfs(int poi,int Last)
{
    if(Last)fa[0][poi]=Last;
    fir[poi]=++su,dep[poi]=dep[Last]+1;
    seq[su]=poi;
    for(int i=last[poi];i;i=e[i].last)
    {
        int u=e[i].to;
        if(u!=Last)dfs(u,poi);
    }
    lst[poi]=++su;
    seq[su]=poi;
}

void update(int &poi,int l,int r,int k,int d)
{
    t[++size]=t[poi];poi=size;
    t[poi].v+=d;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(mid<k)update(t[poi].r,mid+1,r,k,d);
    else update(t[poi].l,l,mid,k,d);
}

void modify(int k,int l,int r,int kk,int d)
{
    for(int i=k;i<=n*2;i+=i&-i)
        update(sroot[i],1,top,kk,d);
}

int lca(int u,int v)
{
    if(dep[u]>dep[v])swap(u,v);
    for(int i=17;i>=0;i--)if( (1<<i) & (dep[v]-dep[u]))v=fa[i][v];
    int dog=17;
    if(u==v)return u;
    while(dog&&fa[0][u]!=fa[0][v])
    {
        if(fa[dog][u]!=fa[dog][v] && fa[dog][u])
        {
            u=fa[dog][u];
            v=fa[dog][v];
        }
        dog--;
    }
    return fa[0][u];
}

int query(int l,int r,int k,int x,int y,int LCA,int FLCA)
{
    if(l==r)return l;
    int num=t[t[x].r].v+t[t[y].r].v-t[t[LCA].r].v-t[t[FLCA].r].v;
    for(int i=1;i<=m1;i++)num+=t[t[L[i]].r].v;
    for(int i=1;i<=m2;i++)num+=t[t[R[i]].r].v;
    for(int i=1;i<=m3;i++)num-=t[t[LL[i]].r].v;
    for(int i=1;i<=m4;i++)num-=t[t[FLL[i]].r].v;
    if(num<k)
    {
        for(int i=1;i<=m1;i++)L[i]=t[L[i]].l;
        for(int i=1;i<=m2;i++)R[i]=t[R[i]].l;
        for(int i=1;i<=m3;i++)LL[i]=t[LL[i]].l;
        for(int i=1;i<=m4;i++)FLL[i]=t[FLL[i]].l;
        return query(l,(l+r)>>1,k-num,t[x].l,t[y].l,t[LCA].l,t[FLCA].l);
    }
    else
    {
        for(int i=1;i<=m1;i++)L[i]=t[L[i]].r;
        for(int i=1;i<=m2;i++)R[i]=t[R[i]].r;
        for(int i=1;i<=m3;i++)LL[i]=t[LL[i]].r;
        for(int i=1;i<=m4;i++)FLL[i]=t[FLL[i]].r;
        return query(((l+r)>>1)+1,r,k,t[x].r,t[y].r,t[LCA].r,t[FLCA].r);
    }
}

int main()
{
    freopen("1146.in","r",stdin);
    freopen("1146.out","w",stdout);
    int m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&v[i]),op[++top]=(ope){v[i],i,0};
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&ask[i].k,&ask[i].x,&ask[i].y);
        if(!ask[i].k)op[++top]=(ope){ask[i].y,i,1};
    }
    sort(1+op,1+op+top,cmp);
    for(int i=1;i<=top;i++)
    {
        if(op[i].flg)ask[op[i].id].y=i;
        else v[op[i].id]=i;
    }
    dfs(1,0);
    pre();
    for(int i=1;i<=n*2;i++)
    {
        root[i]=root[i-1];
        update(root[i],1,top,v[seq[i]],fir[seq[i]]==i?1:-1);
    }
    for(int i=1;i<=m;i++)
    {
        if(i==2000)
        {
            i=2000;
        }
        if(!ask[i].k)
        {
            modify(fir[ask[i].x],1,top,v[ask[i].x],-1);
            modify(lst[ask[i].x]+1,1,top,v[ask[i].x],1);
            v[ask[i].x]=ask[i].y;
            modify(fir[ask[i].x],1,top,v[ask[i].x],1);
            modify(lst[ask[i].x]+1,1,top,v[ask[i].x],-1);
        }
        else{
            int LCA=lca(ask[i].x,ask[i].y);
            tot=dep[ask[i].x]+dep[ask[i].y]-dep[LCA]-dep[fa[0][LCA]];
            if(tot<ask[i].k)
            {
                puts("invalid request!");
                continue;
            }
            m1=m2=m3=m4=0;
            for(int j=fir[ask[i].x];j;j-=j & -j)L[++m1]=sroot[j];
            for(int j=fir[ask[i].y];j;j-=j & -j)R[++m2]=sroot[j];
            for(int j=fir[LCA];j;j-=j & -j)LL[++m3]=sroot[j];
            for(int j=fir[fa[0][LCA]];j;j-=j & -j)FLL[++m4]=sroot[j];
            printf("%d\n",op[query(1,top,ask[i].k,root[fir[ask[i].x]],root[fir[ask[i].y]],root[fir[LCA]],root[fir[fa[0][LCA]]])].v);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值