• 块状树


    BZOJ4765

    将树按深度分为sqrt(n)条可相互重叠的链

    修改时在树上链块外在全局的分块上修改,块内打标记。O(sqrt(n))

    询问时先取分快答案,然后枚举所有链,对答案的贡献为标记之和*链锁对的位置在询问中的数量

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #define ULL unsigned long long 
    using namespace std;
    
      int maxdep[110001],dep[110001],nd[110001],next[210001],des[210001],blsize;
      int speid[110001],cnt,spe[110001],n,m,root,fa[110001],pre[501][110001],fa_spe[110001];
      ULL ori[110001],a[110001],sum[110001],toadd[110001];
      int bt[110001];
    
      void addedge(int x,int y){
          next[++cnt]=nd[x];des[cnt]=y;nd[x]=cnt;
      }
    
      void dfs1(int po){
          maxdep[po]=dep[po];
          bt[po]=1;
          for (int p=nd[po];p!=-1;p=next[p])
          if (!bt[des[p]]){
            dep[des[p]]=dep[po]+1;
            fa[des[p]]=po;
            dfs1(des[p]);
            ori[po]+=ori[des[p]];
            maxdep[po]=max(maxdep[po],maxdep[des[p]]);
        }
        
        if (maxdep[po]-dep[po]>=blsize){
          speid[po]=++cnt;
          spe[po]=1;maxdep[po]=dep[po];    
        }
      }
    
      int main(){
          scanf("%d%d",&n,&m);
          for (int i=1;i<=n;i++) scanf("%llu",&ori[i]),a[i]=ori[i],nd[i]=-1;
          for (int i=1;i<=n;i++){
            int t1,t2;
            scanf("%d%d",&t1,&t2);
            if (t1==0) root=t2;else
            if (t2==0) root=t1;else
            addedge(t1,t2),addedge(t2,t1);
        }
        
        blsize=sqrt(n);
        dep[root]=1;
        cnt=0;
        dfs1(root);
        
        spe[0]=1;
        for (int i=1;i<=n;i++)
          if (spe[i]){
            int po=i;pre[speid[i]][po]=1;po=fa[po];
            while (!spe[po]){
              pre[speid[i]][po]++;
              po=fa[po];    
            }
            for (int j=1;j<=n;j++)
              pre[speid[i]][j]+=pre[speid[i]][j-1];
            fa_spe[i]=po;    
          }
          
        for (int i=1;i<=n;i++) sum[i/blsize+1]+=ori[i];
        
        int quecnt=0;
        for (int i=1;i<=m;i++){
          ULL t1,t2,t3;
          scanf("%llu%llu%llu",&t1,&t2,&t3);
          if (t1==2){
              quecnt++;
              ULL ans=0;
              for (int i=1;i<=cnt;i++) ans+=toadd[i]*(ULL)(pre[i][t3]-pre[i][t2-1]);
              while (t2%blsize&&t2<=t3) ans+=ori[t2],t2++;
              while (t3%blsize&&t3>=t2) ans+=ori[t3],t3--;
            if (t3>=t2) ans+=ori[t3--];
              if (t3>=t2) for (int i=t2/blsize+1;i<=t3/blsize+1;i++) ans+=sum[i];
              printf("%llu
    ",ans);
          }else{
              ULL su=t3-a[t2];a[t2]=t3;
              int po=t2;
              while (!spe[po]){
                ori[po]+=su;
              sum[po/blsize+1]+=su;
              po=fa[po];    
            }
            while (po){
              toadd[speid[po]]+=su;
              po=fa_spe[po];
            }
          }    
        }
      }
  • 相关阅读:
    PHP 面试踩过的坑(三)
    明天准备离职了,面对照顾自己的领导,要这样说
    别怕!MySQL引起的CPU消耗过大,我有办法
    值得收藏:一份非常完整的 MySQL 规范(一)
    emacs 快捷键设置 基础知识篇
    Ruby快速入门(三):控制语句
    Ruby快速入门(一):安装、运行、类和对象
    Ruby快速入门(二):变量、数字、数组和运算符
    Ruby快速入门(四):类和模块
    emacs安装autocomplete插件
  • 原文地址:https://www.cnblogs.com/zhujiangning/p/6529292.html
Copyright © 2020-2023  润新知