zoukankan      html  css  js  c++  java
  • BZOJ 4867 分块+神tm卡常

    思路:

    注意到len<=10

    按照权值max-min<=sqrt(n)*len 分块
    记一下前缀和  每修改sqrt(n)次以后重新分块
     
    修改的时候整块打标记  两边重构
    (这题常数卡得要死   找同学要来fread才过)

     查询的时候 就 二分答案 O(sqrt(n))判断

    二分的上界要实时根据maxdeep变化才能过

    //By SiriusRen
    #include<bits/stdc++.h>
    using namespace std;
    const int N=100050;
    int n,m,op,xx,yy,len,limval,Block,deep[N],cnt,dfn[N],lst[N],maxdep;
    int first[N],next[N],v[N],w[N],tot,a[N],pos[N],maxx[N],minn[N],L[N],R[N],tag[N];
    unsigned short sum[1200][33333];
    inline int nextChr() {
        static const int siz=1<<22;
        static char buf[siz],*chr=buf+siz;
        if(chr==buf+siz)fread(chr=buf,1,siz,stdin);
        return int(*chr++);
    }
    inline int read(){
        register int r=0,c=nextChr();
        for(;c<48;c=nextChr());
        for(;c>47;c=nextChr())r=(r<<3)+(r<<1)+c-48;
        return r;
    }
    inline void add(int x,int y,int z){w[tot]=z,v[tot]=y,next[tot]=first[x],first[x]=tot++;}
    void dfs(int x){
        dfn[x]=++cnt,a[cnt]=deep[x];
        for(int i=first[x];~i;i=next[i])
            deep[v[i]]=deep[x]+w[i],dfs(v[i]);
        lst[x]=cnt;
    }
    void rebuild(int x){
        for(int i=0;i<=limval;i++)sum[x][i]=0;maxx[x]=0;
        for(int i=L[x];i<=R[x];i++)sum[x][a[i]]++,maxx[x]=max(maxx[x],a[i]);
        for(int i=1;i<=maxx[x];i++)sum[x][i]+=sum[x][i-1];
    }
    void build(){
        int bs=0;limval=n*len/Block;maxdep=0;
        for(int i=1;i<=n;i++)a[i]=a[i]+tag[pos[i]],maxdep=max(maxdep,a[i]);
        for(int i=1;i<=n;){
            bs++,L[bs]=R[bs]=i,maxx[bs]=minn[bs]=a[i];
            while(i<=n&&max(maxx[bs],a[i])-min(minn[bs],a[i])<=limval&&R[bs]-L[bs]<=Block)
                R[bs]=i,pos[i]=bs,maxx[bs]=max(maxx[bs],a[i]),minn[bs]=min(minn[bs],a[i]),i++;
        }
        for(int i=1;i<=bs;i++){
            maxx[i]-=(tag[i]=minn[i]);
            for(int j=L[i];j<=R[i];j++)a[j]-=tag[i];
            rebuild(i);
        }
    }
    void change(int l,int r,int wei){
        if(pos[l]==pos[r]){for(int i=l;i<=r;i++)a[i]+=wei;rebuild(pos[l]);}
        else{
            for(int i=l;i<=R[pos[l]];i++)a[i]+=wei;rebuild(pos[l]);
            for(int i=L[pos[r]];i<=r;i++)a[i]+=wei;rebuild(pos[r]);
            for(int i=pos[l]+1;i<=pos[r]-1;i++)tag[i]+=wei;
        }
    }
    int kth(int l,int r,int wei){
        int ans=0;
        if(pos[l]==pos[r]){for(int i=l;i<=r;i++)ans+=(tag[pos[l]]+a[i]<=wei);}
        else{
            for(int i=l;i<=R[pos[l]];i++)ans+=(tag[pos[l]]+a[i]<=wei);
            for(int i=L[pos[r]];i<=r;i++)ans+=(tag[pos[r]]+a[i]<=wei);
            for(int i=pos[l]+1;i<=pos[r]-1;i++)if(wei>=tag[i])
                ans+=sum[i][min(maxx[i],wei-tag[i])];
        }return ans;
    }
    int bsrch(int l,int r,int k){
        if(r-l+1<k)return -1;
        int lft=0,rit=maxdep,ans=-1;
        while(lft<=rit){
            int mid=(lft+rit)>>1;
            if(kth(l,r,mid-1)+1<=k)lft=mid+1,ans=mid;
            else rit=mid-1;
        }return ans;
    }
    int main(){
        memset(first,-1,sizeof(first));
        n=read(),m=read(),len=read(),Block=min(n,(int)sqrt(n));
        for(int i=2;i<=n;i++)xx=read(),yy=read(),add(xx,i,yy);
        dfs(1),build();
        while(m--){
            if(cnt>Block)cnt=0,build();
            op=read(),xx=read(),yy=read();
            if(op==1)printf("%d
    ",bsrch(dfn[xx],lst[xx],yy));
            else limval+=yy,maxdep+=yy,change(dfn[xx],lst[xx],yy),cnt++;
        }
    }
  • 相关阅读:
    PERL 学习
    javascript
    Netfilter
    PHP内核探索
    Linux内存管理学习笔记 转
    使用mysqladmin ext 了解MySQL运行状态 转
    在ArcGIS Desktop中进行三参数或七参数精确投影转换
    AE 栅格图分级渲染
    ArcEngine标注和注记
    ArcGIS Engine 线段绘制
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6767835.html
Copyright © 2011-2022 走看看