loj6046 「雅礼集训 2017 Day8」爷
最近遇到几个分块题,我发现我一遇到分块题就死活构造不出来
不对,明明是,遇到数据结构题,就死活构造不出来。
所以我就找了几个分块题做做。
其实分块,树上的,很多都是先求一个dfs序,或者树剖,用一个log的代价或者没有多余的代价变成序列上的东西
树上的东西想到dfs序和树剖不是套路么……
很多不好维护的东西,都可以用分块来做,诶这不是我以前说过的么。
这道题,如果分块,那么按照套路,块内就可以排序,我们可以二分一个答案,然后在块内二分。
算了算复杂度,2个log,一个根号,不是很优秀的样子。
而题面上说$k \leq 10$,肯定有阴谋!
我们想,如果一个块内,元素最小最大值之差不大,我们就可以直接开个数组记录前缀和就好了,少一个log呢。
于是我们就,每次块内大小$>sz$或者最小值最大值之差$>S$,我们就新开一个块。
然后每隔一段时间重新分一下块,这样就非常优秀啦。
一开始自己智障,把$S$设得有点大,T掉了。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<ctime> #include<set> using namespace std; #define ll long long #define db double #define For(i,a,b) for(register int i=(a);i<=(b);++i) #define Rep(i,a,b) for(register int i=(a);i>=(b);--i) const int maxn=2e5+7,maxt=1000+7,maxs=2e4+7,S=2e3,INF=0x3f3f3f3f; int n,m,len,a[maxn],bel[maxn],sz; int L[maxn],R[maxn]; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[maxn],to[maxn],e=0,v[maxn]; void add(int x,int y,int z) { to[++e]=y;nxt[e]=fir[x];fir[x]=e;v[e]=z; } int dfn[maxn],fed[maxn],dfn_clock; void dfs(int pos,int d) { dfn[pos]=++dfn_clock; a[dfn_clock]=d; for(int y=fir[pos];y;y=nxt[y]) dfs(to[y],d+v[y]); fed[pos]=dfn_clock; } int sum[maxt][maxs],pl[maxt],pr[maxt],tot; int d[maxn]; inline void pd(int x) { if(!d[x]) return; For(i,L[x],R[x]) a[i]+=d[x]; d[x]=0; } inline void ud(int x) { pl[x]=INF; pr[x]=-INF; For(j,L[x],R[x]) { pl[x]=min(pl[x],a[j]); pr[x]=max(pr[x],a[j]); } For(j,0,pr[x]-pl[x]) sum[x][j]=0; For(j,L[x],R[x]) ++sum[x][a[j]-pl[x]]; For(j,1,pr[x]-pl[x]) sum[x][j]+=sum[x][j-1]; } void bld() { For(i,1,tot) pd(i); int now=1,ld=INF,rd=-INF; L[1]=1; For(i,1,n) { ld=min(ld,a[i]); rd=max(rd,a[i]); if(rd-ld>S||i-L[now]>=sz) { R[now]=i-1; L[++now]=i; ld=rd=a[i]; } R[bel[i]=now]=i; } tot=now; For(i,1,tot) ud(i); } inline int get_sum(int p,int x) { if(x<pl[p]) return 0; if(x>pr[p]) return sum[p][pr[p]-pl[p]]; return sum[p][x-pl[p]]; } inline int q(int ld,int rd,int x) { int rs=0,lt=bel[ld],rt=bel[rd]; if(lt==rt) { For(i,ld,rd) if(a[i]<=x) ++rs; return rs; } if(ld!=L[lt]) {For(i,ld,R[lt]) if(a[i]<=x) ++rs;} else rs+=get_sum(lt,x); if(rd!=R[rt]) {For(i,L[rt],rd) if(a[i]<=x) ++rs;} else rs+=get_sum(rt,x); For(i,lt+1,rt-1) rs+=get_sum(i,x); return rs; } inline int Yth(int ld,int rd,int k) { int lt=bel[ld],rt=bel[rd]; pd(lt); pd(rt); if(rd-ld+1<k) return -1; int l=INF,r=-INF,mid; For(i,lt,rt) l=min(l,pl[i]),r=max(r,pr[i]); if(l==r) return l; --l; while(l<r-1) { mid=(l+r)>>1; if(q(ld,rd,mid)>=k) r=mid; else l=mid; } return r; } inline void chge(int ld,int rd,int x) { int lt=bel[ld],rt=bel[rd]; if(lt==rt) { pd(lt); For(i,ld,rd) a[i]+=x; ud(lt); return; } if(ld!=L[lt]) { pd(lt); For(i,ld,R[lt]) a[i]+=x; ud(lt); } else d[lt]+=x,pl[lt]+=x,pr[lt]+=x; if(rd!=R[rt]) { pd(rt); For(i,L[rt],rd) a[i]+=x; ud(rt); } else d[rt]+=x,pl[rt]+=x,pr[rt]+=x; For(i,lt+1,rt-1) d[i]+=x,pl[i]+=x,pr[i]+=x; } int main() { read(n); read(m); read(len); sz=300; int op,x,y; For(i,2,n) { read(x); read(y); add(x,i,y); } dfs(1,0); bld(); For(i,1,m) { read(op); read(x); read(y); if(op==1) printf("%d\n",Yth(dfn[x],fed[x],y)); else chge(dfn[x],fed[x],y); if(i%1000==0) bld(); } return 0; }
弱者就是会被欺负呀