1000問到達おめでとうございます。
https://yukicoder.me/problems/no/1000
問題
整数列Aと、同じ長さで全要素0の数列Bが与えられる。
以下のクエリを順次行った後のBの値を求めよ。
- Aの1要素A[x]にyを加算する
- 現在のA[L...R]の値をB[L...R]に加算する
解法
最初Aが空で、代わりにAの初期値を設定する前者のクエリがあると考えよう。
後者のクエリが行われると、各要素に「これ以前に行われた前者にクエリの総和だけ、最終的な解に加算される」ということになる。
このクエリ群を逆に行うことを考える。
BITやSegTreeを使い、「後者のクエリが以後何回実行されるか」の総和を求めていこう。
逆に前者のクエリに遭遇した時、「後者のクエリが以後何回実行されるか」がわかっているので、その分解に加算すればよい。
int N,Q; template<class V, int ME> class BIT { public: V bit[1<<ME]; V operator()(int e) {if(e<0) return 0;V s=0;e++;while(e) s+=bit[e-1],e-=e&-e; return s;} void add(int e,V v) { e++; while(e<=1<<ME) bit[e-1]+=v,e+=e&-e;} }; BIT<int,20> num; ll A[202020]; string C[202020]; ll X[202020],Y[202020]; ll ret[202020]; void solve() { int i,j,k,l,r,x,y; string s; cin>>N>>Q; FOR(i,N) cin>>A[i+1]; FOR(i,Q) { cin>>C[i]>>X[i]>>Y[i]; } for(i=Q-1;i>=0;i--) { if(C[i]=="A") { ret[X[i]]+=num(X[i])*Y[i]; } else { Y[i]++; num.add(X[i],1); num.add(Y[i],-1); } } for(i=1;i<=N;i++) cout<<(ret[i]+A[i]*num(i))<<" "; }
まとめ
逆順に気付けばすんなり。