首页 > 代码库 > BZOJ 4867 分块+神tm卡常
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\n",bsrch(dfn[xx],lst[xx],yy)); else limval+=yy,maxdep+=yy,change(dfn[xx],lst[xx],yy),cnt++; }}
BZOJ 4867 分块+神tm卡常
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。