kmjp's blog

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

Codeforces #174 Div1 D. Tourists

方針はすぐ立ったけど、割と実装が面倒な問題。
http://codeforces.com/contest/286/problem/D

問題

2次元座標で(-1,0)、(1,0)にいる2人が、ある時点からY座標正方向に速度1で移動する。
ここで、M個の壁がある。各壁は時刻T[i]に瞬間的に(0,L[i])-(0,R[i])を結ぶ線分上に登場する。
移動中の2人を結んだ線分上に、登場済みの壁が存在する場合、2人は互いの姿を見られない。

ここでN個のクエリがあり、各クエリは2人の移動開始時刻Q[i]で与えられる。
各クエリに対し、2人が互いの姿を確認できない時間を答えよ。

解法

姿を見える見えないと考えると一見ややこしいが、要は時刻(Q[i]+p)の時点でY座標(0,p)に壁があるような時間の和を求める問題である。

まず壁のY座標を圧縮した配列PP[i]を作成し各区間(0,PP[i])-(0,PP[i+1])に壁ができる最速の時間CT[i]を求める。
ここで出発時刻をtとすると、この区間は以下のように確認できない時間に影響する。

  • t ≦ CT[i]-PP[i+1]なら、この区間は壁ができる前に通過するので、確認できない時間は0。
  • t ≧ CT[i]-PP[i]なら、この区間に踏み込んだ時点ですでに壁ができているので、区間通過中(PP[i+1]-PP[i])の時間だけ確認できない。
  • その間、CT[i]-PP[i+1] < t < CT[i]-PP[i]なら、区間通過中に壁ができ、確認できない時間はt-(CT[i]-PP[i+1])とtの一次関数となる。

各クエリについて、各区間ごとに上記値を加算すればよい。
このままだとO(NM)かかるので、先にクエリをソートしておく。
後はtの係数成分と定数成分でimos法を用いれば計算量を落とすことができる。

座標圧縮がO(M*logM)、imos法のための成分指定がO(M*logN)、クエリのソートがO(N*logN)。
NとMの上限はほぼ同じなので、大体O(M*logM)で済む。

int N,M;
ll L[100020],R[100020],T[100020];
ll Q[100020];
vector<pair<ll,ll> > QP;
ll PP[200200];
ll AS[200200],BS[200200],ret[200200];
vector<ll> S[200200],E[200200];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>M;
	FOR(i,M) cin>>L[i]>>R[i]>>T[i];
	FOR(i,N) cin>>Q[i], QP.push_back(make_pair(Q[i],i));
	sort(QP.begin(),QP.end());
	
	// compress
	map<ll,ll> UM;
	UM[0]=0;
	FOR(i,M) UM[L[i]]=UM[R[i]]=1;
	i=0;
	ITR(it,UM) it->second=i++, PP[it->second]=it->first;
	FOR(i,M) S[UM[L[i]]].push_back(T[i]),E[UM[R[i]]].push_back(T[i]);
	
	map<ll,int> CS;
	FOR(i,UM.size()) {
		FOR(j,E[i].size()) if(--CS[E[i][j]]==0) CS.erase(E[i][j]);
		FOR(j,S[i].size()) CS[S[i][j]]++;
		if(CS.size()) {
			ll ct=CS.begin()->first;
			x=lower_bound(QP.begin(),QP.end(),make_pair(ct-PP[i+1],0LL))-QP.begin();
			y=lower_bound(QP.begin(),QP.end(),make_pair(ct-PP[i],0LL))-QP.begin();
			AS[x]++; AS[y]--;
			BS[x]-=ct-PP[i+1], BS[y]+=ct-PP[i];
		}
	}
	
	ll aa=0,bb=0;
	FOR(i,N) aa+=AS[i], bb+=BS[i], ret[QP[i].second]=aa*QP[i].first+bb;
	FOR(i,N) cout<<ret[i]<<endl;
}

まとめ

これはすんなり方針が立って良かった。
tの係数成分のimos法が自力で書けたしね。