• dtoj#4258. 铃铛计数问题


    题目描述:

    圣诞节来了,仓鼠又要来策划活动了,今年仓鼠会在圣诞树上挂上铃铛!

    已知圣诞树有 $n$ 个节点,并且根节点是固定的。记 $s[i]$ 表示以 $i$ 为根的子树中,所有节点上铃铛数目的总和。但仓鼠觉得询问 $s[i]$ 太简单了,他决定给定 $l$ 和 $r$,要你回答 $sumlimits_{i=l}^{r}s[i]$ 的值。

    但是为了避免有的人一次预处理后一劳永逸,仓鼠在大家答题的过程中还会修改某个节点上灯笼的数量。仓鼠还要去筹备活动,你能帮助他写一个程序帮助实时给出标准答案吗?

    算法标签:分块

    思路:

    分块好题。

    比较容易想到分块处理,但是这题要把各个部分分开算。

    $cnt[x][i]$ 表示在第 $i$ 个块,有多少个点在 $x$ 到根的链上,那么每次修改 $val[x]$ 就会发生 $cnt[x][i] imes (new-val[x])$ 的权值变化。

    对于单个点价值的计算,按照 $dfn$ 序做前缀和,单点修改区间查询,考虑再分一次块,对于每一次修改,对整个块有影响的对于这个块统一加一个值,否则单点加。那么一次查询效率就是 $O(1)$ 的了。

    以下代码:

    #include<bits/stdc++.h>
    #define il inline
    #define LL long long
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=1e5+5,M=320;
    LL res[M],sum[N],tag[M],g[N];
    int gr[N],sz,num[M][N],dfn[N],ed[N],tot;
    int n,Q,val[N],rt,head[N],ne[N<<1],to[N<<1],cnt;
    il int read(){
       int x,f=1;char ch;
       _(!)ch=='-'?f=-1:f;x=ch^48;
       _()x=(x<<1)+(x<<3)+(ch^48);
       return f*x;
    }
    il void ins(int x,int y){
        ne[++cnt]=head[x];
        head[x]=cnt;to[cnt]=y;
    }
    il void dfs(int x,int fa){
        for(int i=1;i<=gr[n];i++)num[i][x]=num[i][fa];
        num[gr[x]][x]++;dfn[x]=++tot;
        sum[tot]=sum[tot-1]+val[x];g[x]=val[x];
        for(int i=head[x];i;i=ne[i]){
            if(fa==to[i])continue;
            dfs(to[i],x);g[x]+=g[to[i]];
        }
        ed[x]=tot;res[gr[x]]+=g[x];
    }
    il LL cal(int x){
        return sum[ed[x]]-sum[dfn[x]-1]+tag[gr[ed[x]]]-tag[gr[dfn[x]-1]];
    }
    il void change(int x,int v){
        for(int i=1;i<=gr[n];i++)res[i]+=1ll*v*num[i][x];
        int p=dfn[x];
        for(int i=gr[p]+1;i<=gr[n];i++)tag[i]+=v;
        for(int i=p;i<=min(n,gr[p]*sz);i++)sum[i]+=v;
    }
    il LL query(int l,int r){
        LL ans=0;
        if(gr[l]==gr[r]){
            for(int i=l;i<=r;i++)ans+=cal(i);
            return ans;
        }
        for(int i=l;i<=gr[l]*sz;i++)ans+=cal(i);
        for(int i=(gr[r]-1)*sz+1;i<=r;i++)ans+=cal(i);
        for(int i=gr[l]+1;i<gr[r];i++)ans+=res[i];
        return ans;
    }
    int main()
    {
        n=read();Q=read();sz=(int)sqrt(n);
        for(int i=1;i<=n;i++)val[i]=read();
        for(int i=1;i<=n;i++)gr[i]=(i-1)/sz+1;
        for(int i=1;i<=n;i++){
            int x=read(),y=read();
            if(x)ins(x,y),ins(y,x);
            else rt=y;
        }
        dfs(rt,0);
        while(Q--){
            int op=read(),l=read(),r=read();
            if(op==1){
                change(l,r-val[l]);val[l]=r;
            }
            else{
                printf("%lld
    ",query(l,r));
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    32位系统最大只能支持4GB内存之由来
    无线传感器网络中的节点定位技术
    Python 面向对象编程(一)
    Eclipse+PyDev+Django+Mysql搭建Python web开发环境
    Python中的函数(二)
    关于raw_input()和sys.stdin.readline()的区别
    Python中的函数(三)
    将Sublime Text 2搭建成一个好用的IDE
    Windows Phone 7 Tips (1)
    Expression Blend 知识锦分享
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10562365.html
Copyright © 2020-2023  润新知