loj6046 「雅礼集训 2017 Day8」爷

https://loj.ac/problem/6046

最近遇到几个分块题,我发现我一遇到分块题就死活构造不出来

不对,明明是,遇到数据结构题,就死活构造不出来。

所以我就找了几个分块题做做。

其实分块,树上的,很多都是先求一个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;
}

  

posted @ 2018-06-21 19:37  shixinyi  阅读(538)  评论(0编辑  收藏  举报