LOJ2570 [ZJOI2017]线段树


传送门

#include 
const int N=800005,W=19;
typedef long long ll;
int f[N][W+1],l[N],r[N],sl[N],sr[N],ls[N],rs[N],deep[N],cnt,rt,pos[N],n,Q,u,L,R;
ll suml[N],sumr[N];
int build(int fa,int L,int R){
	int k=++cnt;
	f[k][0]=fa;
	l[k]=L,r[k]=R;
	if (L==R){
		pos[L]=k;
		return k;
	}
	int mid;
	scanf("%d",&mid);
	ls[k]=build(k,L,mid);
	rs[k]=build(k,mid+1,R);
	return k;
}
int LCA(int x,int y){
	if (deep[x]=0;i--)
		if (deep[f[x][i]]>=deep[y]) x=f[x][i];
	if (x==y) return x;
	for (int i=W;i>=0;i--)
		if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}
void dfs(int x){
	if (ls[x]){
		int u=ls[x];
		deep[u]=deep[x]+1;
		sl[u]=sl[x]+1;
		suml[u]=suml[x]+deep[u];
		sr[u]=sr[x];
		sumr[u]=sumr[x];
		dfs(u);
	}
	if (rs[x]){
		int u=rs[x];
		deep[u]=deep[x]+1;
		sl[u]=sl[x];
		suml[u]=suml[x];
		sr[u]=sr[x]+1;
		sumr[u]=sumr[x]+deep[u];
		dfs(u);
	}
}
bool issub(int x,int y){
	return l[y]<=l[x] && r[x]<=r[y]; 
}
ll call(int u,int x){
	ll ans=suml[x]+(ll)deep[u]*sl[x];
	int lca=LCA(u,x);
	ll now=(ll)(sl[x]-sl[lca])*deep[lca];
	if (issub(u,rs[lca]) && lca!=x) now++;
	now=now+suml[lca]-sl[lca];
	return ans-now*2;
}
ll calr(int u,int x){
	ll ans=sumr[x]+(ll)deep[u]*sr[x];
	int lca=LCA(u,x);
	ll now=(ll)(sr[x]-sr[lca])*deep[lca];
	if (issub(u,ls[lca]) && lca!=x) now++;
	now=now+sumr[lca]-sr[lca];
	return ans-now*2;
}
ll solve(int u,int L,int R){
	int lca=LCA(L,R);
	return call(u,L)-call(u,ls[lca])+calr(u,R)-calr(u,rs[lca]);
}
int main(){
	scanf("%d",&n);
	build(0,1,n);
	pos[0]=++cnt;
	f[cnt][0]=cnt+1;//0
	rt=++cnt;
	l[rt]=0,r[rt]=n+1;//0-n+1 
	ls[rt]=pos[0],rs[rt]=cnt+1;
	cnt++,f[cnt][0]=rt,l[cnt]=1,r[cnt]=n+1;//1-n+1
	ls[cnt]=1,rs[cnt]=cnt+1;f[1][0]=cnt;
	cnt++;l[cnt]=r[cnt]=n+1;pos[n+1]=cnt;
	f[cnt][0]=cnt-1;//n+1-n+1
	for (int i=1;i<=W;i++)
		for (int j=1;j<=cnt;j++)
			f[j][i]=f[f[j][i-1]][i-1];
	dfs(rt);
	scanf("%d",&Q);
	while (Q--){
		scanf("%d%d%d",&u,&L,&R);
		L=pos[L-1],R=pos[R+1];
		printf("%lld\n",solve(u,L,R));
	}
}