kmjp's blog

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

Codeforces ECR #078 : D. Segment Tree

Dから急に難易度が上がった回。
https://codeforces.com/contest/1278/problem/D

問題

N個の区間が与えられる。
同じ座標に複数の区間の端点が来ることはない。

N頂点のグラフを考える。
頂点u-v間は、前述の区間のu番目とv番目が共通部分を持つとき辺を持つとする。
このグラフは木になるか判定せよ。

解法

区間を端点順にソートして端から走査していけば、辺を愚直につなげていくことができる。
これだと最悪辺がO(N^2)本できかねないが、N辺以上登場した時点で木でないことが確定するので、そこで調査を打ち切ることができる。

template<int um> class UF {
	public:
	vector<int> par,rank,cnt;
	UF() {par=rank=vector<int>(um,0); cnt=vector<int>(um,1); for(int i=0;i<um;i++) par[i]=i;}
	void reinit() {int i; FOR(i,um) rank[i]=0,cnt[i]=1,par[i]=i;}
	int operator[](int x) {return (par[x]==x)?(x):(par[x] = operator[](par[x]));}
	int count(int x) { return cnt[operator[](x)];}
	int operator()(int x,int y) {
		if((x=operator[](x))==(y=operator[](y))) return x;
		cnt[y]=cnt[x]=cnt[x]+cnt[y];
		if(rank[x]>rank[y]) return par[x]=y;
		rank[x]+=rank[x]==rank[y]; return par[y]=x;
	}
};
UF<500000> uf;

int N,num;
int L[505050],R[505050];
int C[1010101];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N;
	FOR(i,N) {
		cin>>L[i]>>R[i];
		C[L[i]-1]=i;
		C[R[i]-1]=i+N;
	}
	
	set<pair<int,int>> alive;
	int E=0;
	FOR(i,2*N) {
		x=C[i];
		if(x<N) {
			alive.insert({-L[x],x});
		}
		else {
			x-=N;
			FORR(a,alive) {
				y=a.second;
				if(x==y) break;
				E++;
				if(uf[y]==uf[x]) return _P("NO\n");
				uf(y,x);
				if(E>=N) return _P("NO\n");
			}
			alive.erase({-L[x],x});
		}
	}
	if(E!=N-1) return _P("NO\n");
	cout<<"YES"<<endl;
		
	
}

まとめ

本番いろいろ頑張って結局TLEでHackされたんだよな…。