• LOJ#6046. 「雅礼集训 2017 Day8」爷


    Description

    给你一个$n$个点的有根树,$1$为根,带边权,有$m$次操作。

    求$x$的子树中第$k$小的深度的值,如果子树中没有$k$个点则输出$-1$;
    将$x$与$x$父亲的边权加上$k$。
    保证每次操作 2 的$k$以及原树的边权小于等于一个数$len$。

    如果操作 2 中$x$为$1$,那么视为将$x$的基础深度加上了$k$。

    Solution

    先用dfs序将其转化为区间上的问题

    如果直接分块并在块内排序,每次查找时二分答案再在每个块内二分,复杂度是$O(n sqrt{n} log^2 n)$的

    题中说边权以及每次加的值不是很大

    可以控制每个块内极差在一定范围内,维护块内前缀和,就可以做到查询时复杂度$O(n sqrt{n} log n)$

    需要定期地对整个序列重建分块

    #include<iostream>
    #include<utility>
    #include<cstring>
    #include<vector>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int n,m,K,head[100005],tot,ll[100005],rr[100005],dfn,a[100005],cnt,plz[100005],tik,B,bot[100005],top[100005],sum[1005][16005],bel[100005],bg[100005],ed[100005],sta1[100005],sta2[100005],top1,top2,lim;
    const int inf=0x7f7f7f7f;
    struct Edge{
        int to,nxt,w;
    }edge[200005];
    inline int read(){
        int f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
        return f*w;
    }
    void solve(int id){
        top[id]=-inf,bot[id]=inf;
        for(int j=bg[id];j<=ed[id];j++)top[id]=max(top[id],a[j]),bot[id]=min(bot[id],a[j]);
        memset(sum[id],0,(top[id]-bot[id]+1)<<2);
        for(int j=bg[id];j<=ed[id];j++)++sum[id][a[j]-bot[id]];
        for(int j=1;j<=top[id]-bot[id];j++)sum[id][j]+=sum[id][j-1];
    }
    void rebuild(){
        for(int i=1;i<=n;i++)a[i]+=plz[bel[i]];
        memset(plz,0,(cnt+1)<<2),memset(bg,0,(cnt+1)<<2),cnt=tik=0,cnt=1;
        int maxx=a[1],minn=a[1],len=0;
        for(int i=1;i<=n;i++){
            ++len,bel[i]=cnt,ed[cnt]=i,maxx=max(maxx,a[i+1]),minn=min(minn,a[i+1]);
            if(!bg[cnt])bg[cnt]=i;
            if(maxx-minn+1>=B*K||len>=B||i==n)solve(cnt),maxx=minn=a[i+1],len=0,++cnt;
        }
        --cnt;
    }
    void dfs(int k,int dep){
        ll[k]=++dfn,a[dfn]=dep,lim=max(lim,dep);
        for(int i=head[k];i;i=edge[i].nxt)dfs(edge[i].to,dep+edge[i].w);
        rr[k]=dfn;
    }
    int calc(int x){
        int ret=0;
        for(int i=1;i<=top1;i++){
            if(x<plz[sta1[i]]+bot[sta1[i]])continue;
            if(x>=plz[sta1[i]]+top[sta1[i]])ret+=ed[sta1[i]]-bg[sta1[i]]+1;
            else ret+=sum[sta1[i]][x-plz[sta1[i]]-bot[sta1[i]]];
        }
        for(int i=1;i<=top2;i++)ret+=(sta2[i]<=x);
        return ret;
    }
    int query(int l,int r,int k){
        top1=top2=0;
        for(int i=l;i<=r;i=ed[bel[i]]+1)
            if(i==bg[bel[i]]&&ed[bel[i]]<=r)sta1[++top1]=bel[i];
            else for(int j=i;j<=min(r,ed[bel[i]]);j++)sta2[++top2]=a[j]+plz[bel[i]];
        int L=0,R=lim,ret=0;
        while(L<=R){
            int mid=L+R>>1;
            if(calc(mid)>=k)ret=mid,R=mid-1;
            else L=mid+1;
        }
        return ret;
    }
    void update(int l,int r,int k){
        lim+=k;
        for(int i=l;i<=r;i=ed[bel[i]]+1)
            if(i==bg[bel[i]]&&ed[bel[i]]<=r)plz[bel[i]]+=k;
            else{
                for(int j=i;j<=min(r,ed[bel[i]]);j++)a[j]+=k;
                for(int j=bg[bel[i]];j<=ed[bel[i]];j++)a[j]+=plz[bel[i]];
                plz[bel[i]]=0,solve(bel[i]);
            }
    }
    int main(){
        n=read(),m=read(),K=read(),B=sqrt(n);
        for(int i=2;i<=n;i++){
            int x=read(),w=read();
            edge[++tot]=(Edge){i,head[x],w},head[x]=tot;
        }
        dfs(1,0),rebuild();
        for(;m;m--){
            int opt=read(),x=read(),k=read();
            if(opt==1)printf("%d
    ",rr[x]-ll[x]+1>=k?query(ll[x],rr[x],k):-1);
            else{
                update(ll[x],rr[x],k),++tik;
                if(tik>=1000)rebuild();
            }
        }
        return 0;
    }
    「雅礼集训 2017 Day8」爷
  • 相关阅读:
    用JAVA发送一个XML格式的HTTP请求
    LR 测试http协议xml格式数据接口
    软件测试术语
    linux学习笔记
    接口测试文章整理
    InputStream只能读取一次的解决办法 C# byte[] 和Stream转换
    zTree更新自定义标签>>>
    C# 各类常见Exception 异常信息
    C# 调用存储过程 Sql Server存储过程 存储过程报错,程序中的try
    SQL Server 2014 清除用户名和密码
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14531760.html
Copyright © 2020-2023  润新知