【BZOJ1146】网络管理(整体二分)

17 篇文章 0 订阅

题面

良心洛谷,有BZOJ权限题

题解

要看树套树的戳这里

毕竟是:智商不够数据结构来补

所以,
我们来当一回智商够的选手

听说主席树的题目大部分都可以整体二分

这题丢进去整体二分就行了
只需要查询树上贡献的前缀和
但是,对于这种带修改的
不能够直接修改
每一个修改操作必须拆成两个:
一个删掉原来的修改,一个加入现在的修改
否则就会重复计算贡献从而 gg

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 81000
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int dfn[MAX],low[MAX],fa[MAX],size[MAX],hson[MAX],dep[MAX],top[MAX];
int tim,n,Q;
int LCA(int u,int v)
{
    while(top[u]!=top[v])
        dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];
    return dep[u]<dep[v]?u:v;
}
void dfs1(int u,int ff)
{
    size[u]=1;fa[u]=ff;dep[u]=dep[ff]+1;
    for(int i=h[u];i;i=e[i].next)
    {
        if(e[i].v==ff)continue;
        dfs1(e[i].v,u);
        size[u]+=size[e[i].v];
        if(size[e[i].v]>size[hson[u]])hson[u]=e[i].v;
    }
}
void dfs2(int u,int tp)
{
    top[u]=tp;dfn[u]=++tim;
    if(hson[u])dfs2(hson[u],tp);
    for(int i=h[u];i;i=e[i].next)
    {
        if(e[i].v==fa[u]||e[i].v==hson[u])continue;
        dfs2(e[i].v,e[i].v);
    }
    low[u]=tim;
}
int sum,ans[MAX];
struct Op{int k,a,b,id,opt;}O[MAX<<1],p1[MAX<<1],p2[MAX<<1];
int c[MAX],TT[MAX];
int lowbit(int x){return x&(-x);}
void add(int x,int w){while(x<=n)c[x]+=w,x+=lowbit(x);}
int getsum(int x){int ret=0;while(x)ret+=c[x],x-=lowbit(x);return ret;}
int jump(int u,int v)
{
    int ret=0;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]])swap(u,v);
        ret+=getsum(dfn[u])-getsum(dfn[top[u]]-1);
        u=fa[top[u]];
    }
    if(dep[u]<dep[v])swap(u,v);
    ret+=getsum(dfn[u])-getsum(dfn[v]-1);
    return ret;
}
void Work(int L,int R,int l,int r)
{
    if(L>R)return;
    if(l==r)
    {
        for(int i=L;i<=R;++i)
            if(!O[i].opt&&ans[O[i].id]!=-1)ans[O[i].id]=l;
        return;
    }
    int mid=(l+r)>>1;
    int t1=0,t2=0;
    for(int i=L;i<=R;++i)
    {
        if(O[i].k==0)
        {
            if(O[i].b<=mid)p1[++t1]=O[i];
            else p2[++t2]=O[i],add(dfn[O[i].a],O[i].id);
        }
        else
        {
            int ss=jump(O[i].a,O[i].b);
            if(ss>=O[i].k)p2[++t2]=O[i];
            else O[i].k-=ss,p1[++t1]=O[i];
        }
    }
    for(int i=L;i<=R;++i)if(O[i].opt&&O[i].b>mid)add(dfn[O[i].a],-O[i].id);
    for(int i=1;i<=t1;++i)O[L+i-1]=p1[i];
    for(int i=1;i<=t2;++i)O[L+t1+i-1]=p2[i];
    Work(L,L+t1-1,l,mid);Work(L+t1,R,mid+1,r);
}
int main()
{
    n=read();Q=read();
    int Cnt=0;
    for(int i=1;i<=n;++i)
    {
        TT[i]=read();
        O[++Cnt]=(Op){0,i,TT[i],1,1};
    }
    for(int i=1;i<n;++i)
    {
        int u=read(),v=read();
        Add(u,v);Add(v,u);
    }
    dfs1(1,0);dfs2(1,1);
    for(int i=1;i<=Q;++i)
    {
        int k=read(),a=read(),b=read();
        if(k)
        {
            O[++Cnt]=(Op){k,a,b,++sum,0};
            int len=dep[O[Cnt].a]+dep[O[Cnt].b]-2*dep[LCA(O[Cnt].a,O[Cnt].b)]+1;
            if(O[Cnt].k>len)ans[O[Cnt].id]=-1;
        }
        else
        {
            O[++Cnt]=(Op){0,a,TT[a],-1,1};
            O[++Cnt]=(Op){0,a,TT[a]=b,1,1};
        }
    }
    Work(1,Cnt,1,1e8);
    for(int i=1;i<=sum;++i)
        ans[i]!=-1?printf("%d\n",ans[i]):puts("invalid request!");
    return 0;   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值