代码改变世界

华华开始学信息学

2019-04-07 23:28  一只弱鸡丶  阅读(408)  评论(0编辑  收藏  举报

题目链接: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\n",ans);
        }
    }
    return 0;
}
View Code