zoukankan      html  css  js  c++  java
  • 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(nsqrt{n})$

    查询时中间直接查询,两端暴力,$O(sqrt{n}log n)$

    总复杂度$O(nsqrt{n}+qsqrt{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
    ",ask(l+1,r+1,z+1)%201314);
      return 0;
    }
    

      

  • 相关阅读:
    字符编码与解码详解
    【Java反射机制】用反射改进简单工厂模式设计
    数据结构
    根据 中序遍历 和 后序遍历构造树(Presentation)(C++)
    【动态规划】记忆搜索(C++)
    Linux环境下安装中山大学东校区iNode客户端
    webpack前端开发环境搭建
    CSS中line-height继承问题
    MySQL中MyISAM与InnoDB的主要区别对比
    JavaScript中易混淆的DOM属性及方法对比
  • 原文地址:https://www.cnblogs.com/clrs97/p/4403232.html
Copyright © 2011-2022 走看看