Codeforces 377(#222 Div1) D. Developing Game

問題

n人の人からなるべく大きい人数のグループを作る。
i番目の人はスキルがsiである。この人は、グループの他人全員のスキルがli以上ri以下じゃなければグループに入らない。
最大で何人のグループができるか。

制約条件

n≦10^5
0≦li≦ri≦si≦3*10^5

方針

L, Rを固定してスキルが[L, R]の人だけを使うと考える。
すると、li≦L, L≦si≦R, R≦riが成り立っている人が使える。


L, Rを全部試すのは無理なので、Lを動かしながら人数が効率的に求められないか考えてみる。
人間をliの小さい順に並べておく。
Lを大きくしたとき、

  • li≦Lになって、新たに使えるようになったiを考えている集合に入れる。
  • si<Lになってしまい使えなくなったiを集合から外す。


後者の管理は、集合に入っている人をpriority_queueで持てば速くできる。
で、新たに人(si, ri)が使えるようになったとき、
答えは、si≦R≦riが成り立つような範囲のRのとき1増える。
つまり、segment木で区間[si, ri]に1を足してやる。


で、最大値は全区間上でのsegment木の最大値になる。
解の復元が要求されているので、最大値を実現したRもsegment木が返すようにする。


segment木のRMQに区間の加算をできるようにするには、遅延評価を入れればよい。

ソースコード

const pi UNDEF(0, -1);

template<class T>struct SegTree{
	
	T *dat;
	int n, *add;
	SegTree(int size = 1000000){
		for(n = 1; n < size; n *= 2);
		dat = new T[2 * n - 1];
		add = new int[2 * n - 1];
		init();
	}
	~SegTree(){ delete [] dat; }
	
	void init(){
		memset(add, 0, sizeof(int) * (2 * n - 1));
		rep(i, n) dat[i + n - 1] = pi(0, i);
		for(int i = n - 2; i >= 0; i--) dat[i] = max(dat[i * 2 + 1], dat[i * 2 + 2]);
	}
	inline void plus(int a, int b, int k, int l, int r, int x){
		if(r <= a || b <= l) return;
		if(a <= l && r <= b){
			add[k] += x;
			return;
		}
		if(add[k]){
			add[k * 2 + 1] += add[k];
			add[k * 2 + 2] += add[k];
			add[k] = 0;
		}
		plus(a, b, k * 2 + 1, l, (l + r) / 2, x);
		plus(a, b, k * 2 + 2, (l + r) / 2, r, x);
		
		T c = dat[k * 2 + 1], d = dat[k * 2 + 2];
		c.first += add[k * 2 + 1]; d.first += add[k * 2 + 2];
		dat[k] = max(c, d);
	}
	inline void plus(int a, int b, int x){ plus(a, b, 0, 0, n, x); }
	inline T query(int a, int b, int k, int l, int r){
		if(r <= a || b <= l) return UNDEF;
		if(a <= l && r <= b){
			T res = dat[k];
			res.first += add[k];
			return res;
		}
		if(add[k]){
			add[k * 2 + 1] += add[k];
			add[k * 2 + 2] += add[k];
			add[k] = 0;
		}
		T vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
		T vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
		
		return max(vl, vr);
	}
};

const int MX = 100000;
int n, l[MX], sk[MX], r[MX];

int main(){
	scanf("%d", &n);
	vector<pair<int, pi> > v;
	rep(i, n){
		scanf("%d%d%d", l + i, sk + i, r + i);
		v.pb(mp(l[i], mp(sk[i], r[i])));
	}
	sort(all(v));
	priority_queue<pi, vector<pi>, greater<pi> > in;
	SegTree<pi> tree(3 * 100010);
	
	int ans = 0, ml = -1, mr = -1;
	
	rep(it, v.size()){
		
		int L = v[it].first;
		in.push(v[it].second);
		tree.plus(v[it].second.first, v[it].second.second + 1, 1);
		
		
		while(in.size() && in.top().first < L){
			
			int l = in.top().first, r = in.top().second; in.pop();
			tree.plus(l, r + 1, -1);
		}
		pi mx = tree.query(0, tree.n, 0, 0, tree.n);
		if(mx.first > ans){
			ans = mx.first;
			ml = L; mr = mx.second;
		}
	}
	printf("%d\n", ans);
	rep(i, n) if(ml <= sk[i] && sk[i] <= mr && l[i] <= ml && mr <= r[i])
		printf("%d%c", i + 1, --ans ? ' ' : '\n');
	
	return 0;
}