読者です 読者をやめる 読者になる 読者になる

hogloidのブログ

へなちょこ

2831 Can we build this one?

http://poj.org/problem?id=2831
N村を結ぶM辺があり、最小全域木を作る
そのとき、ある辺のコストがCならその辺は最小全域木に選ばれうるか、という
クエリを処理する問題


id:semiexpさんの http://d.hatena.ne.jp/semiexp/20110107/1294381308 こちらの方が想定解だと思いますが、
この解法ではクラスカル法で辺を50処理するごとにその状態を記録して、一番近いところから
探索を再び始める、という方法をとっています
O(MlogM+A(M)+Q(log(M/50)+A(50)))

struct uf{
	vi rank,p;
	uf(int n){
		rank.resize(n,1);
		p.resize(n,-1);
	}
	int root(int a){
		if(p[a]==-1) return a;
		return p[a]=root(p[a]);
	}
	bool same(int a,int b){
		return root(a)==root(b);
	}
	void unite(int a,int b){
		a=root(a);b=root(b);
		if(a==b) return;
		if(rank[a]>rank[b]) p[b]=a;
		else{
			p[a]=b;
			if(rank[a]==rank[b]) ++rank[b];
		}
	}
};
int sq=50;
int main(){
	int n,m,q;scanf("%d%d%d",&n,&m,&q);
	vector<pair<int,pi> >es(m),es2;
	REP(i,m){
		int a,b,c;scanf("%d%d%d",&a,&b,&c);
		--a;--b;
		es[i]=mp(c,mp(a,b));
	}
	es2=es;
	sort(ALL(es2));
	uf u(n);
	vector<uf> point(2002,uf(n));
	REP(i,es2.size()){
		if(i%sq==0){
			point[i/sq]=u;
		}
		u.unite(es2[i].sc.fr,es2[i].sc.sc);
	}
	uf bef(0);
	REP(i,q){
		int road,x;scanf("%d%d",&road,&x);
		--road;
		pair<int,pi> r=es[road];
		r.fr=x;
		int ub=(m+sq-1)/sq,lb=0;
		while(ub-lb>1){
			int md=(ub+lb)/2;
			if(es2[md*sq].fr>=r.fr) ub=md;
			else lb=md;
		}
		int suc=0;
		bef=point[lb];
		if(!bef.same(r.sc.sc,r.sc.fr)){
		REP(j,sq){
			if(lb*sq+j==m){suc=1;break;}
			if(es2[lb*sq+j].fr<r.fr){
				bef.unite(es2[lb*sq+j].sc.fr,es2[lb*sq+j].sc.sc);
				if(bef.same(r.sc.sc,r.sc.fr)) break;
			}else{
				suc=1;break;
			}
			if(j==sq-1){suc=1;break;}
		}
		}
		if(suc) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

超絶無駄実装!!