[BZOJ4876][ZJOI2017]线段树
没有用到任何算法,代码只有60+行,但是细节多如牛毛,各种分类讨论必须全部想清楚才行。
https://www.cnblogs.com/xiejiadong/p/6811289.html
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=l; i<=r; i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=800100; 8 ll n,nd,tot,m,u,l,r,S,mid[N],ls[N],rs[N],sm[N][2],dep[N],sd[N][2],fa[N][20],L[N],R[N],pos[N]; 9 10 bool bel(int x,int y){ return L[x]>=L[y] && R[x]<=R[y]; } 11 ll lca(ll a,ll b){ 12 if (bel(a,b)) return b; 13 if (bel(b,a)) return a; 14 ll now=a; 15 for (ll i=S; ~i; i--) if (fa[now][i] && !bel(b,fa[now][i])) now=fa[now][i]; 16 return fa[now][0]; 17 } 18 19 void Dfs(ll x){ 20 if (!ls[x]) return; 21 sm[rs[x]][0]=sm[x][0]; sm[rs[x]][1]=sm[x][1]+1; 22 sm[ls[x]][0]=sm[x][0]+1; sm[ls[x]][1]=sm[x][1]; 23 dep[ls[x]]=dep[rs[x]]=dep[x]+1; 24 sd[rs[x]][0]=sd[x][0]; sd[rs[x]][1]=sd[x][1]+dep[x]+1; 25 sd[ls[x]][0]=sd[x][0]+dep[x]+1; sd[ls[x]][1]=sd[x][1]; 26 Dfs(ls[x]); Dfs(rs[x]); 27 } 28 29 ll dfs(ll l,ll r){ 30 ll x=++nd; L[x]=l; R[x]=r; 31 for (ll i=0; fa[fa[x][i]][i]; i++) fa[x][i+1]=fa[fa[x][i]][i]; 32 if (l==r) return pos[l]=x; 33 ll m=mid[tot++]; 34 fa[nd+1][0]=x; ls[x]=dfs(l,m); 35 fa[nd+1][0]=x; rs[x]=dfs(m+1,r); 36 return x; 37 } 38 39 ll getl(ll l){ 40 ll lc=lca(l,u),x=dep[lc]*(sm[l][0]-sm[lc][0])+(bel(l,ls[lc]) && lc!=u)+sd[lc][0]-sm[lc][0]; 41 return sd[l][0]+sm[l][0]*dep[u]-x*2; 42 } 43 44 ll getr(ll r){ 45 ll lc=lca(r,u),x=dep[lc]*(sm[r][1]-sm[lc][1])+(bel(r,rs[lc]) && lc!=u)+sd[lc][1]-sm[lc][1]; 46 return sd[r][1]+sm[r][1]*dep[u]-x*2; 47 } 48 49 int main(){ 50 freopen("segment.in","r",stdin); 51 freopen("segment.out","w",stdout); 52 scanf("%lld",&n); 53 for (ll i=1; i<=n; i<<=1) S++; 54 for (ll i=1; i<n; i++) scanf("%lld",&mid[i]); 55 tot=1; dfs(1,n); Dfs(1); 56 for (scanf("%lld",&m); m--; ){ 57 scanf("%lld%lld%lld",&u,&l,&r); l--; r++; 58 if (!l && r>n) { printf("%lld\n",dep[u]); continue; } 59 ll ans=0; 60 if (l) ans+=getl(pos[l])-((r<=n)?getl(ls[lca(pos[l],pos[r])]):0); 61 if (r<=n) ans+=getr(pos[r])-(l?getr(rs[lca(pos[l],pos[r])]):0); 62 printf("%lld\n",ans); 63 } 64 return 0; 65 }