Description
Input
第一行给出两个整数N,M。分别表示序列长度和操作个数
接下来一行有N个数,即给定的序列a1,a2,....an
接下来M行,每行对应一个操作,格式见题目描述
Output
对于每个询问操作,输出一行,表示所询问的SSi的值。
Sample Input
5 3
1 2 3 4 5
Query 5
Modify 3 2
Query 5
1 2 3 4 5
Query 5
Modify 3 2
Query 5
Sample Output
35
32
32
HINT
1<=N,M<=100000,且在任意时刻0<=Ai<=100000
本来想用树状数组维护前缀和再枚举的。。。
神tm这和暴力好像没什么不一样啊
树状数组又不能支持区间修改
等等,好像可以用容斥原理做
c[x]=1+2+3+4+...+x
cc[x]=n*1+(n-1)*2+....+x
那么答案就是cc[x]-(n-x)*c[x];
代码如下:
#include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; ll a[210000]; ll c[210000],cc[210000]; ll lowbit(ll x){return x&(-x);} int n,m; void change(ll x,ll d) { int N=(n-x+1); while(x<=n) { c[x]+=d;cc[x]+=N*d; x+=lowbit(x); } } char st[15]; ll getsum(ll x) { ll sum=0,ans=0;int N=n-x; while(x>=1) { sum+=cc[x],ans+=c[x]; x-=lowbit(x); } return sum-N*ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%lld",&a[i]),change(i,a[i]); while(m--) { scanf("%s",st+1); if(st[1]==‘M‘) { ll x,y; scanf("%lld%lld",&x,&y); change(x,y-a[x]); a[x]=y; } else { ll x; scanf("%lld",&x); printf("%lld\n",getsum(x)); } } return 0; }
by_lmy