bzoj4867: [Ynoi2017]舌尖上的由乃
Posted ccz181078
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4867: [Ynoi2017]舌尖上的由乃相关的知识,希望对你有一定的参考价值。
用dfs序转为区间加,区间第k大
分块,块内维护排序后的权值,并记录每个权值原来在块中的位置。加法操作对于整块可以打标记,零散部分因为记了每个值排序前的位置,可以直接提取出块中待修改的部分,修改后用归并排序线性重构这个块,对于查询,先把零散部分提取出来,当作普通的块处理,然后二分答案,在每个块上再二分<k的个数。
块大小取$O(\sqrt{n}logn)$时时间复杂度达到最优$O(m\sqrt{n}logn)$。
#include<cstdio> #include<cmath> #include<algorithm> const int N=100007; char buf[10000000],*ptr=buf-1; int _(){ int x=0,c=*++ptr; while(c<48)c=*++ptr; while(c>47)x=x*10+c-48,c=*++ptr; return x; } int n,m,len,B; int es[N],enx[N],e0[N],ep=2,ee[N]; int id[N][2],idp=0; int ls[N],rs[N],ws[N]; struct val{ int w,v; }a[N],a1[N],a2[N],a0[N]; int aa[N]; bool operator<(const val&a,const val&b){ return a.v<b.v; } void f1(int w,int dep){ id[w][0]=++idp; a[idp]=(val){idp,dep+=ee[w]}; for(int i=e0[w];i;i=enx[i])f1(es[i],dep); id[w][1]=idp; } void merge(val*v1,int m1,val*v2,int m2,val*v){ int p1=0,p2=0; while(p1<m1&&p2<m2)*v++=v1[p1].v<v2[p2].v?v1[p1++]:v2[p2++]; while(p1<m1)*v++=v1[p1++]; while(p2<m2)*v++=v2[p2++]; } void add(int w,int L,int R,int k){ int l=ls[w],r=rs[w],p1=0,p2=0; int aa1=aa[w]+k,aa2=aa[w]; aa[w]=0; for(int i=l;i<=r;++i){ if(L<=a[i].w&&a[i].w<=R)(a1[p1++]=a[i]).v+=aa1; else (a2[p2++]=a[i]).v+=aa2; } merge(a1,p1,a2,p2,a+l); } void add(int L,int R,int k){ int l=ws[L],r=ws[R]; add(l,L,R,k); if(l!=r)add(r,L,R,k); for(int i=l+1;i<r;++i)aa[i]+=k; } int get(int w,int L,int R,val*v){ int l=ls[w],r=rs[w],p=0; for(int i=l;i<=r;++i)if(L<=a[i].w&&a[i].w<=R)(v[p++]=a[i]).v+=aa[w]; return p; } void mins(int&a,int b){if(a>b)a=b;} void maxs(int&a,int b){if(a<b)a=b;} int lss(val*a,int p,int x){ int L=0,R=p; while(L<R){ int M=L+R>>1; if(a[M].v<=x)L=M+1; else R=M; } return L; } void query(int L,int R,int k){ if(R-L+1<k){ puts("-1"); return; } int l=ws[L],r=ws[R],p; if(l==r)p=get(l,L,R,a0); else{ int p1=get(l,L,R,a1); int p2=get(r,L,R,a2); merge(a1,p1,a2,p2,a0); p=p1+p2; } int mn=0x7fffffff,mx=-mn; if(p)mn=a0[0].v,mx=a0[p-1].v; for(int i=l+1;i<r;++i)mins(mn,a[ls[i]].v+aa[i]),maxs(mx,a[rs[i]].v+aa[i]); while(mn<mx){ int x=mn+(mx-mn>>1); int c=lss(a0,p,x); for(int i=l+1;i<r;++i)c+=lss(a+ls[i],rs[i]-ls[i]+1,x-aa[i]); if(c<k)mn=x+1; else mx=x; } printf("%d\n",mn); } int main(){ fread(buf,1,sizeof(buf),stdin)[buf]=0; n=_();m=_();len=_(); B=sqrt(n+1)*log2(n+1)*0.371+1; for(int i=2;i<=n;++i){ int f=_(); ee[i]=_(); es[ep]=i;enx[ep]=e0[f];e0[f]=ep++; } f1(1,0); for(int l=1,r=B,c=1;l<=n;l+=B,r+=B,++c){ if(r>n)r=n; for(int i=l;i<=r;++i)ws[i]=c; ls[c]=l;rs[c]=r; std::sort(a+l,a+r+1); } while(m--){ if(_()==1){ int x=_(),k=_(); query(id[x][0],id[x][1],k); }else{ int x=_(),k=_(); add(id[x][0],id[x][1],k); } } return 0; }
以上是关于bzoj4867: [Ynoi2017]舌尖上的由乃的主要内容,如果未能解决你的问题,请参考以下文章