BZOJ3626 : [LNOI2014]LCA
求[l,r]内所有点与z的lca的深度之和 = 求z所有祖先子树中在[l,r]内的点的个数之和
由于数据不是随机的,所以祖先个数可能很大。
按编号分成$\sqrt{n}$块
设ans[i][j]表示第i块内所有点与j的lca的深度之和
计算ans[i][]时,把在[l,r]内所有点的cnt设为1,其它的设为0,
然后从下往上,父亲的cnt+=孩子的cnt,
然后再从上往下,孩子的cnt+=父亲的cnt
最后ans[i][j]就等于cnt[j]
预处理$O(n\sqrt{n})$
查询时中间直接查询,两端暴力,$O(\sqrt{n}\log n)$
总复杂度$O(n\sqrt{n}+q\sqrt{n}\log n)$
然后一开始写了倍增求lca被卡常数了TAT
然后改成了用树链剖分求lca后就过了!(而且答案本身就在int范围内所以最后再取模即可)
恩以后都打树链剖分了。
#include<cstdio> #define N 50010 #define M 230 int n,q,i,j,x,z,l,r,f[N],d[N],g[N],v[N],nxt[N],ed,cnt[N],heavy[N],son[N],top[N],lim,block,st[M],en[M],pos[N],ans[M][N]; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline void swap(int&x,int&y){int z=x;x=y;y=z;} inline void add(int x,int y){v[++ed]=y,nxt[ed]=g[x],g[x]=ed;} void dfs1(int x){ cnt[x]=1;d[x]=d[f[x]]+1; int heavy=0,max=0,i; for(i=g[x];i;i=nxt[i]){ dfs1(v[i]),cnt[x]+=cnt[v[i]]; if(cnt[v[i]]>max)max=cnt[v[i]],heavy=v[i]; } if(heavy)son[x]=heavy; } void dfs2(int x,int t){ top[x]=t; if(son[x])dfs2(son[x],t); for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x])dfs2(v[i],v[i]); } inline int lca(int x,int y){ while(top[x]!=top[y]){ if(d[top[x]]<d[top[y]])swap(x,y); x=f[top[x]]; } return d[x]<d[y]?d[x]:d[y]; } void up(int x){for(int i=g[x];i;i=nxt[i])up(v[i]),cnt[x]+=cnt[v[i]];} void down(int x,int y){ans[y][x]=cnt[x];for(int i=g[x];i;i=nxt[i])cnt[v[i]]+=cnt[x],down(v[i],y);} inline int ask(int l,int r,int z){ int i,t=0; if(pos[l]==pos[r]){ for(i=l;i<=r;i++)t+=lca(z,i); return t; } for(i=l;i<=en[pos[l]];i++)t+=lca(z,i); for(i=st[pos[r]];i<=r;i++)t+=lca(z,i); for(i=pos[l]+1;i<pos[r];i++)t+=ans[i][z]; return t; } int main(){ read(n),read(q); for(i=2;i<=n;i++)read(f[i]),add(++f[i],i); dfs1(1),dfs2(1,1); while(lim*lim<n)lim++; for(i=1;i<=n;i++)pos[i]=(i-1)/lim+1; for(block=pos[n],i=1;i<=block;i++)en[i-1]=(st[i]=lim*(i-1)+1)-1;en[block]=n; for(i=1;i<=block;i++){ for(j=1;j<st[i];j++)cnt[j]=0; for(j=st[i];j<=en[i];j++)cnt[j]=1; for(j=en[i]+1;j<=n;j++)cnt[j]=0; up(1);down(1,i); } while(q--)read(l),read(r),read(z),printf("%d\n",ask(l+1,r+1,z+1)%201314); return 0; }