码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 4867 分块+神tm卡常

时间:2017-04-26 13:10:52      阅读:316      评论:0      收藏:0      [点我收藏+]

标签:注意   二分答案   else   lin   sre   uil   short   read   r++   

思路:

注意到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\n",bsrch(dfn[xx],lst[xx],yy));
        else limval+=yy,maxdep+=yy,change(dfn[xx],lst[xx],yy),cnt++;
    }
}

 

BZOJ 4867 分块+神tm卡常

标签:注意   二分答案   else   lin   sre   uil   short   read   r++   

原文地址:http://www.cnblogs.com/SiriusRen/p/6767835.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!