HDu 5930 GCD(区間gcdの種類線分樹)
7502 ワード
題名リンク参考解答1009
テーマの大意
n個の数,q回のクエリを与え,そのうちの1つの数を修正するたびに,このn個の数からなるすべてのサブ区間のgcdの種類を尋ねた.
に答える
gcdの種類は最大nlogC(Cは数の最大値)個を超えず、私たちはすべて保存することができ、各gcdがどれだけのサブ区間で構成できるかを併存することができます.区間左端点を列挙し,logC個のgcdが変化する右端点を探して種類と個数を計算し,結果をmapで保存する.
単点修正のたびに,修正されるのはxを含む区間のみであり,それぞれxを区間左端点と区間右端点とし,logCを超えない2つのgcdおよび対応する区間集合を求めることができ,暴力合併するとO((logC)2),mapを修正する時間複雑度を加えるとO((logC)2である.×log(n*logC)).
gcdのlogC個の変化の位置を求めることについて、私のやり方は線分の木を使います.xを左端点として、線分木は[x,N]のgcd変化位置を検索し、まず最初の変化位置はxそのものであり、gcd値はA[x]自身であり、gcd値を再帰関数(gcdvと記す)に伝達し、[le,ri]再帰が必要だ.主なコードは次のとおりです.
上はxを左端に固定するコードで、xを右端に固定するコードは似ています.変化点を求めても線分の木を二分することができますが、TLEができるかもしれません.
このようにして変化点を求める時間の複雑さはO(logn)である.×logC+logC×logC). 暴力合併左と右の区間の時間複雑度はO((logC)×logC×log(n*logC)).しかし、データがlogC個の変化点に達するのは難しいため、3個のlogの時間が複雑でこの問題を乗り越える効率も非常に高い.2つのlogの効率を追求するには、左と右の区間を統合し、統合後の異なるgcdも同様にlogC個であり、mapの値を更新することができます.(合併してmapを新しく開くことはできますが、必要ない感じがします)
テーマの大意
n個の数,q回のクエリを与え,そのうちの1つの数を修正するたびに,このn個の数からなるすべてのサブ区間のgcdの種類を尋ねた.
に答える
gcdの種類は最大nlogC(Cは数の最大値)個を超えず、私たちはすべて保存することができ、各gcdがどれだけのサブ区間で構成できるかを併存することができます.区間左端点を列挙し,logC個のgcdが変化する右端点を探して種類と個数を計算し,結果をmapで保存する.
単点修正のたびに,修正されるのはxを含む区間のみであり,それぞれxを区間左端点と区間右端点とし,logCを超えない2つのgcdおよび対応する区間集合を求めることができ,暴力合併するとO((logC)2),mapを修正する時間複雑度を加えるとO((logC)2である.×log(n*logC)).
gcdのlogC個の変化の位置を求めることについて、私のやり方は線分の木を使います.xを左端点として、線分木は[x,N]のgcd変化位置を検索し、まず最初の変化位置はxそのものであり、gcd値はA[x]自身であり、gcd値を再帰関数(gcdvと記す)に伝達し、[le,ri]再帰が必要だ.主なコードは次のとおりです.
int query_right(int w,int le,int ri,int &x,int &y,int v[],int pos[],int &cnt,int gcdv)
{ // gcdv [x,le-1] gcd , gcd
int mid=(le+ri)>>1;
if (x<=le && ri<=y)
{
if (Tree[w] % gcdv==0) return gcdv; // Tree[w] gcdv ,gcd
if (le==ri) // ,
{
gcdv=gcd(gcdv,Tree[w]);
cnt++;
v[cnt]=gcdv;
pos[cnt]=le;
return gcdv;
}
if (Tree[w<<1]%gcdv!=0)
gcdv=query_right(w<<1,le,mid,x,y,v,pos,cnt,gcdv);
if (Tree[w<<1|1]%gcdv!=0)
gcdv=query_right(w<<1|1,mid+1,ri,x,y,v,pos,cnt,gcdv);
return gcdv;
}
if (mid>=x)
gcdv=query_right(w<<1,le,mid,x,y,v,pos,cnt,gcdv);
if (mid+1<=y)
gcdv=query_right(w<<1|1,mid+1,ri,x,y,v,pos,cnt,gcdv);
return gcdv;
}
上はxを左端に固定するコードで、xを右端に固定するコードは似ています.変化点を求めても線分の木を二分することができますが、TLEができるかもしれません.
このようにして変化点を求める時間の複雑さはO(logn)である.×logC+logC×logC). 暴力合併左と右の区間の時間複雑度はO((logC)×logC×log(n*logC)).しかし、データがlogC個の変化点に達するのは難しいため、3個のlogの時間が複雑でこの問題を乗り越える効率も非常に高い.2つのlogの効率を追求するには、左と右の区間を統合し、統合後の異なるgcdも同様にlogC個であり、mapの値を更新することができます.(合併してmapを新しく開くことはできますが、必要ない感じがします)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include