HL分解
Latest Author IL_msta /Date 2018-02-13 22:40:48 / Views 1488・注意 イメージで実装した。 間違っている可能性に注意 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の演算なら、順序に注意して実装しないといけない。