zoukankan      html  css  js  c++  java
  • 华华开始学信息学

    题目链接:https://ac.nowcoder.com/acm/contest/392/F

    作者:fzszkl
    链接:https://ac.nowcoder.com/discuss/160376?type=101&order=time&pos=&page=1
    来源:牛客网

    考虑用树状数组暴力维护,单次修改的复杂度为O(NX×logN)O(NX×log⁡N)。

    X越大的时候,复杂度越低,可以直接用树状数组来维护。

    X越小的时候,复杂度过高,但是这样的X比较有限,可以开一个桶来维护被修改的总量。

    假设界限为S,那么修改复杂度为O(NS×logN)O(NS×log⁡N),询问复杂度为O(S+logN)O(S+log⁡N),显然S=NlogNS=Nlog⁡N的时候,复杂度最优,为O(NNlogN)O(NNlog⁡N)。

    本题还可以使用定期重构解决,将阈值设为S=NlogNS=Nlog⁡N,复杂度一样,实际效率更高。

    感谢csyer验题时提出以下做法:

    建一个树状数组,第i位记录i的倍数被增加的数的和(只记一次,比如2的倍数就记在2的位置,不需要修改4、6等),设为FiFi。将每次询问看成两端前缀和相减,那么我们要求的就是区间[1,X]的答案,显然就是Xi=1Xi×Fi∑i=1X⌊Xi⌋×Fi。求值时数论分块,使用树状数组进行区间求和即可。修改复杂度O(logN)O(log⁡N),询问复杂度O(n×logN)O(n×log⁡N),因为数论分块和树状数组的复杂度上界比较松,所以效率比较高。

    #include <bits/stdc++.h>
    using namespace std;
    #define re register
    #define ll long long
    const int maxn=1e5+10;
    void read(int &a)
    {
        a=0;
        int d=1;
        char ch;
        while(ch=getchar(),ch>'9'||ch<'0')
            if(ch=='-')
                d=-1;
        a=ch-'0';
        while(ch=getchar(),ch>='0'&&ch<='9')
            a=a*10+ch-'0';
        a*=d;
    }
    void write(int x)
    {
        if(x<0)
            putchar(45),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    ll tree[maxn],f[maxn];
    int n,m;
    int lowbit(int k)
    {
        return k&-k;
    }
    void add(int x,int k)
    {
        while(x<=n)
        {
            tree[x]+=k;
            x+=lowbit(x);
        }
    }
    ll sum(int x)
    {
        ll ans=0;
        while(x>0)
        {
            ans+=tree[x];
            x-=lowbit(x);
        }
        return ans;
    }
    int main()
    {
        read(n);
        read(m);
        while(m--)
        {
            int a,b,c;
            read(a);
            if(a==1)
            {
                int k=1;
                read(b);
                read(c);
                if(b>=500)
                    while(b*k<=n)
                    {
                        add(b*k,c);
                        k++;
                    }
                else
                    f[b]+=c;
            }
            else
            {
                read(b);
                read(c);
                ll ans=sum(c)-sum(b-1);
                for(re int i=1;i<=500;i++)
                    ans+=(c/i-(b-1)/i)*f[i];
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    闲话: 恭喜园子里的MVP一下, 同时问所有奋斗在技术领域的兄弟过节好~
    随便说两句: 表设计兼一些设计分析的讨论
    是他妈傻子写的么?
    Utility Wish List
    我终于有个偶像了
    也论标准: 统一是啥好事情?
    linux 编程学习笔记(1)搭建c(c++)开发环境
    Immutable Collections(2)ImmutableList<T>实现原理.(上)
    托管代码的进程注入&CLR宿主
    .NET安全揭秘系列博文索引
  • 原文地址:https://www.cnblogs.com/acm1ruoji/p/10668074.html
Copyright © 2011-2022 走看看