1 条题解

  • 0
    @ 2025-8-24 22:04:44

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Leianha
    万般皆下品,惟有透彻高

    搬运于2025-08-24 22:04:44,当前版本为作者最后更新于2019-09-11 11:42:48,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    树状数组

    我们需要求的是i=1kSi\sum_{i=1}^{k}S_i ,即i=1kj=1iai\sum_{i=1}^{k}\sum_{j=1}^{i}a_i.

    暴力求解肯定是不行的,化简式子是OIer的优良传统,所以我们可以考虑化简一下式子。

    我们可以考虑一下每一个元素对前前缀合的贡献,第ii个数被ii~kk之间的每一个SjS_j都计算了一遍,所以它的贡献就是(ki+1)×ai(k-i+1)\times a_i,我们需要求的就是i=1k(ki+1)×ai\sum_{i=1}^{k}(k-i+1)\times a_i

    我们回到单个元素,根据乘法分配率,我们就得到(ki+1)×ai=(k+1)×aii×ai(k-i+1)\times a_i=(k+1)\times a_i-i\times a_i,

    所以$\sum_{i=1}^{k}(k-i+1)\times a_i=\sum_{i=1}^{k}(k+1)\times a_i-\sum_{i=1}^{k}i\times a_i$,

    再将(k+1)(k+1)提出来之后就得到式子(k+1)i=1kaii=1ki×ai(k+1)\sum_{i=1}^{k} a_i-\sum_{i=1}^{k}i\times a_i

    对于i=1kai\sum_{i=1}^{k} a_ii=1ki×ai\sum_{i=1}^{k}i\times a_i我们都能够用树状数组来维护,这样我们就能快速的求出答案啦^_^。

    再考虑修改,只用这样写

    add1(x,y-a[x]);add2(x,(y-a[x])*x);
    

    就可以啦~,还是比较简单的。

    最后献上我丑陋的代码

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #define int long long
    using namespace std;
    int n,m,x,y;
    const int N=100010;
    int ans,len;
    int a[N],tr1[N<<1],tr2[N<<1];
    char s[101];
    int read()
    {
    	char ch;int x=0,f=1;
    	while(!isdigit(ch=getchar()))
    	{(ch=='-')&&(f=-f);}
    	while(isdigit(ch))
    	{x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*f;
    }
    int lowbit(int x){return x&(-x);}
    void add1(int pos,int x)
    {
    	for(int i=pos;i<=(N<<1);i+=lowbit(i))tr1[i]+=x;
    }
    void add2(int pos,int x)
    {
    	for(int i=pos;i<=(N<<1);i+=lowbit(i))tr2[i]+=x;
    }
    int ask1(int pos)
    {
    	int lin=0;
    	for(int i=pos;i;i-=lowbit(i))lin+=tr1[i];
    	return lin;
    }
    int ask2(int pos)
    {
    	int lin=0;
    	for(int i=pos;i;i-=lowbit(i))lin+=tr2[i];
    	return lin;
    }
    signed main()
    {
    	cin>>n>>m;
    	for(int i=1;i<=n;++i)
    	{
    		a[i]=read();
    		add1(i,a[i]);add2(i,a[i]*i);
    	}
    	while(m--)
    	{
    		scanf("%s",s+1);
    		if(s[1]=='Q')
    		{
    			x=read();
    			ans=((x+1)*ask1(x)-ask2(x));
    			printf("%lld\n",ans);
    		}
    		else
    		{
    			x=read();y=read();
    			add1(x,y-a[x]);add2(x,(y-a[x])*x);
    			a[x]=y;
    		}
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    3728
    时间
    1000ms
    内存
    500MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者