2018ICPC徐州站網路賽 Ryuji doesn't want to study 思維+字首和+樹狀陣列
阿新 • • 發佈:2018-12-24
做這道題讓我對線段樹和樹狀陣列有了更深的理解。。
主要是維護兩個字首和,一個a[i],一個(n-i+1)*a[i],最後結果減一下。剩下就是注意一些樹狀陣列的操作更改了。
附上通過程式碼:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> using namespace std; #define ll long long const int MAX=112345; ll aa[MAX],s1[MAX],s2[MAX]; ll t1[MAX],t2[MAX]; ll n,q,ans; ll lowbit(ll i) { return i&(-i); } void update1(ll i,ll k) { while(i<=n) { t1[i]+=k; i+=lowbit(i); } } ll query1(ll i) { ll sum=0; while(i>0) { sum+=t1[i]; i-=lowbit(i); } return sum; } void update2(ll i,ll k) { while(i<=n) { t2[i]+=k; i+=lowbit(i); } } ll query2(ll i) { ll sum=0; while(i>0) { sum+=t2[i]; i-=lowbit(i); } return sum; } int main() { while(scanf("%lld%lld",&n,&q)==2) { memset(s1,0,sizeof(s1)); memset(s2,0,sizeof(s2)); memset(t1,0,sizeof(t1)); memset(t2,0,sizeof(t2)); memset(aa,0,sizeof(aa)); for(int i=1;i<=n;i++) { scanf("%lld",&aa[i]); s1[i]=s1[i-1]+aa[i]; s2[i]=(n-i+1)*aa[i]+s2[i-1]; } /*for(int i=1;i<=n;i++) cout<<s1[i]<<" "<<s2[i]<<endl;*/ for(int i=1;i<=n;i++) { update1(i,aa[i]); update2(i,(n-i+1)*aa[i]); } int c;ll a,b; for(int i=1;i<=q;i++) { scanf("%d%lld%lld",&c,&a,&b); if(c==1) { ll k1=query1(b)-query1(a-1); ll k2=query2(b)-query2(a-1); ll t=n-b; //cout<<"k2="<<k2<<" k1="<<k1<<" t="<<t<<endl; ans=k2-t*k1; printf("%lld\n",ans); } else { update1(a,b-aa[a]); update2(a,(n-a+1)*(b-aa[a])); aa[a]=b;//注意不能忘!(因為可能重複更新一個位置的值) } } } return 0; }