• [BZOJ 4765]普通计算姬(分块+树状数组)


    Description

    "奋战三星期,造台计算机"。小G响应号召,花了三小时造了台普通计算姬。普通计算姬比普通计算机要厉害一些
    。普通计算机能计算数列区间和,而普通计算姬能计算树中子树和。更具体地,小G的计算姬可以解决这么个问题
    :给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权
    值和。计算姬支持下列两种操作:
    1 给定两个整数u,v,修改点u的权值为v。
    2 给定两个整数l,r,计算sum[l]+sum[l+1]+....+sum[r-1]+sum[r]
    尽管计算姬可以很快完成这个问题,可是小G并不知道它的答案是否正确,你能帮助他吗?

    Solution

    分块。块内直接统计,单点的sum树状数组暴力加起来

    为了方便修改,g[a][i]表示点a对块[i]的贡献

    另外,好坑啊这题会爆long long

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #define MAXN 100007
    using namespace std;
    typedef unsigned long long LL;
    int n,m,init,num,head[MAXN],g[MAXN][330],cnt=0;
    LL c[MAXN],d[MAXN],sum[MAXN],blocks[330];
    int dfn_clock=0,in[MAXN],out[MAXN],a[MAXN];
    LL read()
    {
        LL x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0';c=getchar();
        }
        return x*f;
    }
    struct Node
    {
        int next,to;
    }Edges[MAXN*2];
    void addedge(int u,int v)
    {
        Edges[++cnt].next=head[u];
        head[u]=cnt;
        Edges[cnt].to=v;
    }
    int lowbit(int x){return x&-x;}
    void add(int pos,int x)
    {
        while(pos<=n)
        {
            c[pos]+=x;
            pos+=lowbit(pos);
        }
    }
    LL query(int pos)
    {
        LL res=0;
        while(pos>0)
        {
            res+=c[pos];
            pos-=lowbit(pos);
        }
        return res;
    }
    void dfs(int u,int f)
    {
        dfn_clock++;in[u]=dfn_clock;
        sum[u]=d[u];
        a[(u-1)/init]++;
        for(int i=0;i<num;i++)
        g[u][i]+=a[i];
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(v==f)continue;
            dfs(v,u);
            sum[u]+=sum[v];
        }
        blocks[(u-1)/init]+=sum[u];
        out[u]=dfn_clock;
        a[(u-1)/init]--;
    }
    void Change(int a,int b)
    {
        add(in[a],b-d[a]);
        for(int i=0;i<num;i++)
        blocks[i]+=(b-d[a])*g[a][i];
        d[a]=b;
    }
    void Query(int a,int b)
    {
        LL res=0;
        if((a-1)/init==(b-1)/init)
        for(int i=a;i<=b;i++)
        res+=query(out[i])-query(in[i]-1);
        else 
        {
            for(int i=(a-1)/init+1;i<=(b-1)/init-1;i++)
            res+=blocks[i];
            for(int i=a;i<((a-1)/init+1)*init+1;i++)
            res+=query(out[i])-query(in[i]-1);
            for(int i=b;i>=((b-1)/init)*init+1;i--)
            res+=query(out[i])-query(in[i]-1);
        }
        printf("%llu
    ",res);
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        n=read(),m=read();
        init=(int)sqrt(n+0.1);
        num=(n-1)/init+1;
        for(int i=1;i<=n;i++)
        d[i]=read();
        int root;
        for(int i=1;i<=n;i++)
        {
            int u=read(),v=read();
            if(!u){root=v;continue;}
            addedge(u,v);
            addedge(v,u);
        }
        dfs(root,0);
        for(int i=1;i<=n;i++)
        add(in[i],d[i]);
        for(int i=1;i<=m;i++)
        {
            int opt=read(),a=read();LL b=read();
            if(opt==1)Change(a,b);
            else Query(a,b);
        }
        return 0;
    }
  • 相关阅读:
    【PAT】B1041 考试座位号(15 分)
    【PAT】B1042 字符统计(20 分)
    【PAT】B1044 火星数字(20 分)
    LeetCode 3Sum Closest
    一定要做的事(备忘)
    LeetCode Integer to Roman
    Container With Most Water
    LeetCode ZigZag Conversion
    LeetCode 5 最长回文子串 Manacher线性算法
    LeetCode Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/Zars19/p/6857038.html
Copyright © 2020-2023  润新知