kmjp's blog

競技プログラミング参加記です

yukicoder : No.1000 Point Add and Array Add

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))<<" ";
		
}

まとめ

逆順に気付けばすんなり。