• #4258. 铃铛计数问题


    题意

    内存限制:256 MiB
    时间限制:2000 ms
    圣诞节来了,仓鼠又要来策划活动了,今年仓鼠会在圣诞树上挂上铃铛!
    已知圣诞树有 $n$ 个节点,并且根节点是固定的。记 $s[i]$ 表示以 $i$ 为根的子树中,所有节点上铃铛数目的总和。但仓鼠觉得询问 $s[i]$ 太简单了,他决定给定 $l$ 和 $r$,要你回答 $sumlimits_{i=l}^{r}s[i]$ 的值。
    但是为了避免有的人一次预处理后一劳永逸,仓鼠在大家答题的过程中还会修改某个节点上灯笼的数量。仓鼠还要去筹备活动,你能帮助他写一个程序帮助实时给出标准答案吗?
    $n,q leq 100000$
    题解
    ①考虑对原编号分块,
    记 $f_{i,j}$ 表示 $i$ 点对 $j$ 块所造成的贡献, $s_j$ 表示 $j$ 这一块的答案
    1)考虑修改
    假设在 $x$ 点上加上 $v$ ,那就利用 $f$ 数组进行对每个 $s_j$ 进行修改
    2)考虑查询
    设查询 $[l,r]$ ,设 $b_l$ 为 $l$ 在的块
    那对于 $[b_l+1,b_r-1]$ 的块可以累加 $s$
    对于剩下的,我们需要每个点 $O(1)$ 求出答案
    ②对 $dfs$ 序进行分块
    设 $sum_i$ 表示 $dfs$ 序不小于 $i$ 的点的权值和
    $tag_j$ 表示这个块的后缀和都要加上的值
    对于修改,我们只需要暴力修改 $x$ 的块的每个 $sum_x$ ,然后再把 $[1,b_x-1]$ 的块的 $tag$ 加上 $v$
    回到原来的问题,每个点对应着一段 $dfs$ 序 $[l,r]$ ,所以它的答案就是 $sum_l+tag_{b_l}-sum_{r+1}-tag_{b_{r+1}}$
    效率 $O(n imes sqrt(n))$

    以下代码

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=100005,M=350;
    int w[N],n,q,rt,hd[N],V[N*2],nx[N*2],c[M];
    int f[N][M],t,tt,B,b[N],Z,in[N],ot[N];
    LL sum[N],tg[M],s[M],A,sz[N];
    void add(int u,int v){
        V[++t]=v;nx[t]=hd[u];hd[u]=t;
    }
    void dfs(int x,int fa){
        sum[in[x]=++tt]=sz[x]=w[x];f[x][b[x]]++;
        for (int i=hd[x];i;i=nx[i])
            if (V[i]!=fa){
                for (int j=1;j<=Z;j++)
                    f[V[i]][j]=f[x][j];
                dfs(V[i],x),sz[x]+=sz[V[i]];
            }
        ot[x]=tt;s[b[x]]+=sz[x];
    }
    int main(){
        scanf("%d%d",&n,&q);B=sqrt(n);
        for (int i=1;i<=n;i++){
            scanf("%d",&w[i]),b[i]=(i-1)/B+1;
            if (b[i]!=b[i-1]) c[b[i-1]]=i-1;
        }
        for (int x,y,i=1;i<=n;i++){
            scanf("%d%d",&x,&y);
            if (!x) rt=y;else add(x,y),add(y,x);
        }
        c[Z=b[n]]=n;dfs(rt,0);
        for (int i=n;i;i--) sum[i]+=sum[i+1];
        for (int op,l,r,j;q--;){
            scanf("%d%d%d",&op,&l,&r);
            if (op&1){
                A=r-w[l];w[l]=r;for (j=1;j<=Z;j++)
                    s[j]+=A*f[l][j];l=in[l];
                for (j=l;b[j]==b[l];j--) sum[j]+=A;
                for (j=b[j];j;j--) tg[j]+=A;continue;
            }
            A=0;for (j=b[l]+1;j<b[r];j++) A+=s[j];
            for (j=l;j<=c[b[l]] && j<=r;j++)
                A+=sum[in[j]]+tg[b[in[j]]]-sum[ot[j]+1]-tg[b[ot[j]+1]];
            if (b[l]<b[r])
                for (j=c[b[r]-1]+1;j<=r;j++)
                    A+=sum[in[j]]+tg[b[in[j]]]-sum[ot[j]+1]-tg[b[ot[j]+1]];
            printf("%lld
    ",A);
        }
        return 0;
    }
  • 相关阅读:
    个人作业——软件产品案例分析
    项目Beta冲刺(团队)随笔集
    【Alpha】随笔集合
    个人作业——软件工程实践总结作业
    用户调查报告
    项目Beta冲刺(团队)总结
    项目Beta冲刺(团队)第七天
    项目Beta冲刺(团队)第六天
    项目Beta冲刺(团队)第五天
    项目Beta冲刺(团队)第四天
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/10567591.html
Copyright © 2020-2023  润新知