先放代碼,日後更。
============================2018.3.21UPD============================
題面在這裏
做法
首先需要了解zkw線段樹的操作過程。(不懂的百度一下)
大概就是從兩個葉節點開始,維護兩個指針,一個指向 左邊一位,一個指向 右邊一位,不停向上跳。然後模仿這個過程同樣在這個廣義線段樹上操作,畫一下圖可以發現,假設 所在葉節點 , 所在葉節點 ,一個線段 會分成的若干個小線段恰好是 鏈上所有左兒子的右兄弟,以及 鏈上所有右兒子的左兄弟。
一定要畫圖!!!多觀察!!!
發現這一點後就很容易了。將一條鏈按 分成兩半,然後大力分類討論,樹上倍增處理一下,細節超多。比如, 和 的情況需要特殊處理,還有 的位置比較特殊的時候也需要判一下。
建議自己推推看qwq。(我當時都是自己想的qwq,感覺想出一道zjoi題自己萌!萌!噠!
代碼
/*
* zkw線段樹的科技;
* 一堆細節;
* 考試一定要對拍!不對拍會死的!
*/
#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define per(i,x,y) for (int i=(x); i>=(y); i--)
#define N 400010
#define ll long long
using namespace std;
ll read(){
char ch=getchar(); ll x=0; int op=1;
for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*op;
}
int n,m,tot,rt,now,clk,a[N],f[N][20],pos[N],in[N],out[N];
ll g[N],h[N],f1s[N],f2s[N],gs[N],hs[N],ans,dep[N];
struct seg{
int l,r,ls,rs,mid;
seg(){ l=r=ls=rs=mid=0; }
}tr[N];
void build(int &o,int l,int r,int d,int fa,bool fl){
o=++tot; in[o]=++clk; tr[o].l=l; tr[o].r=r; dep[o]=d; f[o][0]=fa;
if (!fl){//左兒子
g[o]=g[fa]+d; gs[o]=gs[fa]+1;
h[o]=h[fa]; hs[o]=hs[fa];
f1s[o]=f1s[fa]+d-1; f2s[o]=f2s[fa];
} else{
g[o]=g[fa]; gs[o]=gs[fa];
h[o]=h[fa]+d; hs[o]=hs[fa]+1;
f1s[o]=f1s[fa]; f2s[o]=f2s[fa]+d-1;
}
if (l==r){ pos[l]=o; out[o]=++clk; return; } int k=a[now]; tr[o].mid=k;
if (l<k) now++; build(tr[o].ls,l,k,d+1,o,0);
if (k+1<r) now++; build(tr[o].rs,k+1,r,d+1,o,1);
out[o]=++clk;
}
void print_tree(int u){
printf("id: %d, l=%d, r=%d\n",u,tr[u].l,tr[u].r);
if (tr[u].ls) print_tree(tr[u].ls);
if (tr[u].rs) print_tree(tr[u].rs);
}
int lca(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
int tmp=dep[x]-dep[y];
per (i,18,0) if (tmp>>i&1) x=f[x][i];
if (x==y) return x;
per (i,18,0) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
bool isanc(int x,int y){ return in[x]<=in[y] && out[x]>=out[y]; }
int main(){
/*freopen("B.in","r",stdin);
freopen("B.out","w",stdout);*/
n=read();
rep (i,1,n-1) a[i]=read();
m=read();
now=1; build(rt,1,n,0,0,1);
rep (j,1,18) rep (i,1,tot) f[i][j]=f[f[i][j-1]][j-1];
while (m--){
int u=read(),l=read(),r=read(),x,y,z,w,v,tmp;
ans=0;
if (l==1 && r==n){ printf("%d\n",dep[u]); continue; }
x=pos[l-1]; y=pos[r+1]; tmp=lca(x,y); z=tr[tmp].ls; if (l==1 || r==1) z=1;
if (l!=1){
w=lca(x,u);
if (isanc(w,z)){
ll sum=gs[x]-gs[z];
ans+=g[x]-g[z]+sum*dep[u]-2ll*sum*dep[w];
if (w==z && isanc(tr[w].rs,u)) ans-=2;
} else{
ll sum=gs[x]-gs[w];
ans+=g[x]-g[w]+sum*dep[u]-2ll*sum*dep[w];
sum=gs[w]-gs[z];
ans+=g[w]-g[z]+sum*dep[u]-2ll*(f1s[w]-f1s[z]);
if (isanc(tr[w].rs,u)) ans-=2;
}
}
z=tr[tmp].rs; if (l==1 || r==1) z=1;
if (r!=n){
w=lca(y,u);
if (isanc(w,z)){
ll sum=hs[y]-hs[z];
ans+=h[y]-h[z]+sum*dep[u]-2ll*sum*dep[w];
if (w==z && isanc(tr[w].ls,u)) ans-=2;
} else{
ll sum=hs[y]-hs[w];
ans+=h[y]-h[w]+sum*dep[u]-2ll*sum*dep[w];
sum=hs[w]-hs[z];
ans+=h[w]-h[z]+sum*dep[u]-2ll*(f2s[w]-f2s[z]);
if (isanc(tr[w].ls,u)) ans-=2;
}
}
printf("%lld\n",ans);
}
return 0;
}