Luogu1483

Update

许多人得了 \(60\) 分,而不解原因。\(60\) 分的看过来

其实是因为出题人不讲武德,造假数据,说说是 \(1\le j\le n\),实际上有
\(j=0\) 的情况,而这对于有的算法是毁灭性的打击

思路

根号分治。

设阈值 \(\mathtt{lim}\) ,修改操作在阈值以上时,暴力修是
\(O(\frac n{\mathtt{lim}})\) 的;否则打一个懒惰标记,是 \(O(1)\) 的。

查询时可以乱搞,统计不超过阈值的懒惰标记中对其有影响的部分,再加上其本身已计部分,即可,复杂度 \(O(\mathtt{lim})\);注意特判 \(j=0\)

\(\mathtt{lim}=\sqrt n\) 时,单次操作复杂度是最坏 \(O(\sqrt n)\) 的。

其实可以更好,但请参阅其它题解,这里就不多介绍了。

Code

#include <stdio.h>
typedef long long llt;
typedef unsigned uint;typedef unsigned long long ullt;
typedef bool bol;typedef char chr;typedef void voi;
typedef double dbl;
template<typename T>bol _max(T&a,T b){return(a<b)?a=b,true:false;}
template<typename T>bol _min(T&a,T b){return(b<a)?a=b,true:false;}
const uint lim=1000;
llt Lazy[1005],A[1000005];
int main()
{
	uint n,m,op,x;llt y;scanf("%u%u",&n,&m);
	for(uint i=1;i<=n;i++)scanf("%lld",A+i);
	for(uint i=1;i<=m;i++)
	{
        scanf("%u%u",&op,&x);
        if(op==1)
        {
            scanf("%lld",&y);
            if(x<=lim)Lazy[x]+=y;
            else for(uint j=x;j<=n;j+=x)A[j]+=y;
        }
        else
        {
            if(!x)
            {
                puts("0");
                continue;
            }
            llt ans=A[x];
            for(uint j=1;j<=lim;j++)if(!(x%j))ans+=Lazy[j];
            printf("%lld\n",ans);
        }
    }
	return 0;
}
posted @ 2022-02-14 07:21  myee  阅读(36)  评论(0编辑  收藏  举报