• 铃铛计数问题——分块


    题目

    【题目描述】
    圣诞节来了,仓鼠又要来策划活动了,今年仓鼠会在圣诞树上挂上铃铛!
    已知圣诞树有 $n$ 个节点,并且根节点是固定的。记 $s[i]$ 表示以 $i$ 为根的子树中,所有节点上铃铛数目的总和。但仓鼠觉得询问 $s[i]$ 太简单了,他决定给定 $l$ 和 $r$,要你回答 $sumlimits_{i=l}^{r}s[i]$ 的值。
    但是为了避免有的人一次预处理后一劳永逸,仓鼠在大家答题的过程中还会修改某个节点上灯笼的数量。仓鼠还要去筹备活动,你能帮助他写一个程序帮助实时给出标准答案吗?
    【输入格式】
    第一行为两个整数 $n$ 和 $q$,分别表示圣诞树的节点数和仓鼠操作的次数。
    第二行 $n$ 个正整数,第 $n$ 个数 $w[i]$ 表示初始状态下第 $i$ 号节点的铃铛数。
    接下来 $n$ 行,第 $i$ 行两个正整数 $u[i]$ 和 $v[i]$ ,描述一条树上的边,特别地,$u=0$ 时,表示 $v[i]$ 为圣诞树的根节点。你需要特别注意的是 $u[i]$ 不一定是 $v[i]$ 的父亲节点,也有可能 $v[i]$ 是 $u[i]$ 的父亲节点。
    接下来 $q$ 行,每行三个正整数$op,l,r$。描述 $q$ 组操作。当 $op=1$ 时表示将编号为 $l$ 的节点上的铃铛修改为 $r$;当 $op=2$ 时表示询问 $sum
    limits_{i=l}^{r}s[i]$ 的值。
    【输出格式】
    对于每组询问操作,你需要依据当前圣诞树情况输出该组询问的标准答案,每次询问的答案独占一行。
    【样例输入】
    6 6
    7 4 3 4 9 1
    4 2
    0 1
    2 1
    2 3
    5 3
    6 5
    2 1 3
    1 1 1
    2 3 6
    2 3 5
    1 3 5
    2 6 6
    【样例输出】
    62
    28
    27
    1
    【数据范围与提示】
    对于 $25\%$ 的数据, $n,q le 300$;
    对于 $40\%$ 的数据, $n,q le 3000$;
    对于另外 $10\%$ 的数据,所有操作 $op=2$;
    对于另外 $15\%$ 的数据,所有 $op=2$ 的操作 $l=r$;
    对于 $100\%$ 的数据,$n,q le 100000$ ,每个结点的铃铛数始终不超过 $10^9$。

    题解

    考虑分块

    对原编号分块

    记 $ f(i,j) $ 表示 $ i $ 这个点对块 $ j $ 的贡献,显然是可以由 $fa[i]$ 转移过来

    记 $ res[i] $ 表示 $ i $ 这个块内的子树大小和,那么修改点 $ x $ 为 $ v $ 对块 $ i $ 的贡献为 $ f[x][i] imes v $

    那么查询 $[l,r]$ 时对于完整的快直接加上这个快的 $res[x]$,对于左右两个不完整的块,查询单点贡献即可

    接下来就是如何查询单点的贡献

    对这颗树进行 dfs 时,记下这个点的 dfs 序和子树范围

    记 $sum[i]=sum_{k=1}^i val[k],tag[i] $ 表示 $i$ 这个块前缀和被加的的值

    对单点进行修改时,$i$ 后的块的 $tag$ 直接加上 $v$,暴力修改 $i$ 对这个块内的 $sum$ 的影响

    查询单点的答案即为 $sum[ed[i]]-sum[dfn[i]-1]+tag[a[ed[i]]]-tag[a[dfn[i]-1]]$

    代码

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define cal(i) (sum[ed[i]]-sum[dfn[i]-1]+tag[a[ed[i]]]-tag[a[dfn[i]-1]])
     4 #define _(d) while(d(isdigit(ch=getchar())))
     5 using namespace std;
     6 int R(){
     7     int x;bool f=1;char ch;_(!)if(ch=='-')f=0;x=ch^48;
     8     _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;}
     9 const int N=1e5+5,M=325;
    10 int n,m,f[N][M],head[N],cnt,Rt,Sz,a[N],val[N],Mx,tot,dfn[N],ed[N];
    11 LL sum[N],res[N],sz[N],tag[N];
    12 struct edge{int to,nex;}e[N<<1];
    13 void add(int s,int t){e[++cnt]=(edge){t,head[s]},head[s]=cnt;}
    14 void dfs(int u,int fa){
    15     for(int i=1;i<=Mx;i++)f[u][i]=f[fa][i];
    16     f[u][a[u]]++,dfn[u]=++tot;
    17     sum[tot]=sum[tot-1]+val[u],sz[u]=val[u];
    18     for(int k=head[u],v;k;k=e[k].nex)
    19         if((v=e[k].to)!=fa)
    20             dfs(v,u),sz[u]+=sz[v];
    21     ed[u]=tot,res[a[u]]+=sz[u];
    22     return;
    23 }
    24 void change(int x,int v){
    25     for(int i=1;i<=Mx;i++)res[i]+=1ll*v*f[x][i];
    26     int p=dfn[x];
    27     for(int i=p;i<=min(a[p]*Sz,n);i++)sum[i]+=v;
    28     for(int i=a[p]+1;i<=Mx;i++)tag[i]+=v;
    29     return;
    30 }
    31 LL ask(int l,int r){
    32     LL ans=0;
    33     if(a[l]==a[r]){
    34         for(int i=l;i<=r;i++)ans+=cal(i);
    35         return ans;
    36     }
    37     for(int i=l;i<=min(a[l]*Sz,n);i++)ans+=cal(i);
    38     for(int i=(a[r]-1)*Sz+1;i<=r;i++)ans+=cal(i);
    39     for(int i=a[l]+1;i<a[r];i++)ans+=res[i];
    40     return ans;
    41 }
    42 int main(){
    43     n=R(),m=R(),Sz=sqrt(n);
    44     for(int i=1;i<=n;i++)val[i]=R(),a[i]=(i-1)/Sz+1;
    45     Mx=a[n];
    46     for(int i=1;i<=n;i++){
    47         int u=R(),v=R();
    48         if(!u)Rt=v;
    49         else add(u,v),add(v,u);
    50     }
    51     dfs(Rt,0);
    52     for(int i=1;i<=m;i++){
    53         int op=R(),l=R(),r=R();
    54         if(op==1)
    55             change(l,r-val[l]),val[l]=r;
    56         if(op==2)
    57             printf("%lld
    ",ask(l,r));
    58     }
    59     return 0;
    60 }
    View Code
  • 相关阅读:
    ArrayList和CopyOnWriteArrayList
    UML类关系
    Vmware下mint os的安装
    Java VisualVM无法检测到本地java程序 的 解决办法
    谜之闭包
    虚拟DOM(Virtual DOM)
    ES6箭头函数与普通函数的区别
    HTML中 select 与datalist的异同
    备战前端面试
    javascript获取数组中的最大值/最小值
  • 原文地址:https://www.cnblogs.com/chmwt/p/10567598.html
Copyright © 2020-2023  润新知