Codeforces 59 D. Team Arrangement

問題

3*n人が3人チームをn個作った。
それぞれの人には成績があり、同じ成績の人はいない。

チームの決め方は以下のようである。
まだチームに所属していない人のうち、成績が最も良い人が新しいチームのリーダーになる。
その人は、その人のつけている3*n-1人の優先順位の高い順に、まだチームに所属していない人を2人選ぶ。


それぞれのチームのメンバーおよび、各人の成績が与えられるとき、
k番目の人の優先順位として、ありえるもののうち、辞書順で最小のものを求めよ。

制約条件

n≦100000

方針

k番目の人が、チームリーダーでなければ優先順位は任意でよいので、
1 2 3 … nが辞書順で最小の列となる。


そうでないときは、{チームメイト}+{選ばれていない人}の配列と、
{既に選ばれた人}の配列を、マージソートの要領でマージしてやればよい。
すると、チームメイトが選ばれていない人の前に並び、なおかつ辞書順最小の列が得られる。

ソースコード

int n,k,a[300000];
int team[100000][3],where[300000];
int use[300000];

void run()
{
	cin>>n;
	rep(i,3*n)cin>>a[i], a[i]--;
	rep(i,n)rep(j,3)cin>>team[i][j], where[--team[i][j]]=i;
	cin>>k;
	k--;
	
	memset(use,0,sizeof(use));
	rep(i,3*n){
		if(a[i]==k){
			if(use[a[i]]){
				vi ans;
				rep(j,3*n)if(j!=a[i])ans.pb(j+1);
				rep(j,3*n-1)cout<<ans[j]<<(j==3*n-2?"\n":" ");
				return;
			}
			vi teammate,notselected,selected,ans(3*n-1);
			rep(j,3)if(team[where[a[i]]][j]!=a[i]){
				teammate.pb(team[where[a[i]]][j]+1);
				use[team[where[a[i]]][j]]=-1;
			}
			sort(all(teammate));
			
			rep(j,3*n){
				if(j==a[i]||use[j]<0)continue;
				if(use[j])selected.pb(j+1);
				else notselected.pb(j+1);
			}
			sort(all(selected)); sort(all(notselected));
			teammate.insert(teammate.end(),all(notselected));
			
			merge(all(teammate),all(selected),ans.begin());
			
			rep(j,3*n-1)cout<<ans[j]<<(j==3*n-2?"\n":" ");
			return;
		}
		if(!use[a[i]]){
			rep(j,3)use[team[where[a[i]]][j]]=1;
		}
	}
}