HL分解

Latest Author IL_mstaIL_msta /Date 2018-02-13 22:40:48 / Views 1488
0 (Favした一覧ページはユーザーページから)
・注意
イメージで実装した。
間違っている可能性に注意
HLのヘビーとライトが出てこないことからもお察し。

・HL分解
木をパスに分解する操作
頂点圧縮系データ構造の一つだと思う(フラワーっぽい匂いがする)
(木以外にはどう対応付けするのか分からない)

・やってること
根を設定する。(直径の端にする?)
各頂点をグループ分けする。
なるべく長い[パス]でグループに分割する。
一つの頂点は一つのグループのみに属している。

・長いパスの見つけ方
木の根を決定しているので
各頂点の深さを調べる。//bfsでもdfsでも好きなように
ついでにその頂点の親も記録しておく。//パス作成のため
根の親は[-1]とか親なし判別が出来るようにしておく。
必要な記憶
depth[頂点番号]:=頂点の深さ。根の深さは[0]
oya[頂点番号]:=頂点の根方向の頂点番号。頂点が根の場合、なし[-1]。
HukasaNext():=最も深い頂点から順に、頂点番号を得られるような何か
(深さと頂点番号をセットにして、ソート(NextIndexが必要)とか優先度つきキューとか)

・頂点をグループ分けする。
使う記憶
group[i][j]:=i番目のグループのj番目の頂点番号
groupNo[頂点番号i]:=頂点iが属するグループ番号
groupIndex[頂点番号i]:=グループでのindex位置。方向は任意?。
	(根方向の頂点をindex:0にしたい。)
groupOya[グループ番号]:=グループが繋がっている根方向の頂点番号

頂点から根方向への有向辺で構成された
グラフ構造があると便利かも?親が分かっていればいらない?。
gra[u][i]:頂点uのi番目の辺が繋がっている頂点//使ってない

use[i]:=頂点iがグループ分けされている[T/F]

・手順
gropuNoNow = 0;//現在作ろうとしているグループNo

while(全部の頂点とか、調べるべき頂点がある限り続行){
	v = 最も深い頂点番号;//HukasaNext()
	//次回の為に、次の値が取れるようにする
	//調べたい全ての頂点を調べたらループを抜ける
	
	//分割済みならスキップ
	if( use[v] ) continue;
	
	//group[groupNoNow]の容量を確保,サイズはまだ0
	group.push_back(vector<int>());//とか?
	
	//頂点番号 && 未使用なら続行//注:評価順
	while(v != -1 && use[v] != true){
		//頂点[v]をグループ番号[groupNoNow]に追加
		group[groupNowNow].push_back( v );
		use[v] = true;//グループ分け済みにする。
		v = oya[v];//vの親。根方向へ進む
	}
	//グループの接続先を設定
	groupOya[groupNoNow] = v;
	//反転させたい
	//reverse(group[groupNowNow].begin(),.end());
	int size = group[groupNowNow];
	for(int i=0;i<size;++i){
		//グループ内でのIndexと頂点番号を関連付け
		groupIndex[ group[groupNoNow][i] ] = i;
	}
	
	//グループ番号を一つ増やして次に備える
	groupNoNow = groupNoNow + 1;
}

・使い方
頂点uからvへのなんやかんやしたい。

TYPE result = 0;//0元
while(){
	if( groupNo[u] == groupNo[v] ){
		//同じグループに属している。
		gNo = groupNo[u];//グループ番号
		//group[gNo]
		int indexL = groupIndex[u];
		int indexR = groupIndex[v];
		if( indexL > indexR ){
			swap(indexR,indexL);
		}
		//一直線に並べたので、
		//事前準備をすれば,配列に出来る操作ができる
		//BIT,segmentTree
		なんか[gNo].query(indexL,indexR);//[indexL,indexR]||[indexL,indexR+1)を処理
		//resultに結果を付け加える
		
		//終わったのでループ抜けたい
		break;
	}
	else if( depth[ group[groupNo[u]][0] ] < depth[ group[groupNo[v]][0] ] ){
		//イメージなので特に注意
		//グループの先頭が深い方の頂点を根方向へ進ませる。
		//u,vの深さで比べると進みすぎる場合ある。
		//vを進ませる
		gNo = groupNo[v];//グループ番号
		//uは同じグループでないので
		//根方向へ残りのグループ内全部。
		int indexL = 0;
		int indexR = groupIndex[v];
		
		なんか[gNo].query(indexL,indexR);//[indexL,indexR]を処理
		//resulutに結果を付け加える。
		
		v = groupOya[gNo];//グループの接続先の頂点
	}else{
		//else if( depth[u] < depth[v] ){}と同じようなことやる
	}
}

A*B!=B*Aの演算なら、順序に注意して実装しないといけない。