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;
    }
    

      

  • 相关阅读:
    网站被刷导致404解决
    vim常用
    curl, wget常用选项
    使用paramiko远程登录并执行命令脚本
    批量监测dns是否可用脚本,不可用时并切换
    shell脚本收集服务器基本信息并入库
    沃通SSL证书及国密SSL证书入驻百度云市场
    电子合同,相比纸质合同有哪些好处?
    DV型域名https证书的优点及申请流程
    Chrome 浏览器显示“网站连接不安全”,是什么原因?
  • 原文地址:https://www.cnblogs.com/clrs97/p/4403232.html
Copyright © 2011-2022 走看看