リンクツリー
状態D N都市、道路の数は、各道路は、二つの都市を接続し、一定の長さを有することができます。
最初に、どの道がありません。次に、操作はご注文を完了する必要がありqがあります。
xyが表し:XとYの都市間の尋問路長を、何のルートが存在しない場合、あなたは答える必要-1。
xywを表す:道路の長さWの都市建設の間のxとyを。(すなわち:XY前の動作を説明すれば、答えは確実にすべきである-1)任意パスが存在しないことを確実にするために都市およびX yの間先行。
入力形式
入力の最初の行は2つの正の整数N、Qを含んでいます。
次のQ二つまたは三つの入力の正の整数の列、又はxyw XYような形状、動作を表します。
各行において、スペースで区切られた2つの隣接する数字間。
出力フォーマット
フォームXYの各動作のためには、このクエリへのあなたの答えのために、出力に整数を含む1行を必要としています。
データ範囲
テストポイント1,21,2のために$ nは、Q \当量200 $を確保
テストポイント1,2,3,41,2,3,4のために確保するために$ N、Qの\の当量2000 $その
テストポイント1,2,3,4,5,61,2,3,4,5,6のためにその$ N、Qの\の当量$ 100,000を確保するために、
満足奇数テストポイント:すべてがxyw質問状に形成されているが、XYのような形をすべての質問の後に起こります。
すべてのデータの場合、確実にするためにその$ 1 \当量のn、q個の\当量50万$ wは、すべての正の整数1,000以上ではありません。
LCA
データの構造
link(u,v)
query(u,v)
私たちは、$ \のRIGHTARROWが数回以上$ $ \ RIGHTARROW $オフライン作る(ジャンプする)の周りに聞いてきます
読んで、することができません$ \色{赤}、{「CIN」} $、最初の読み取り専用見える文字CINとして
$の\カラー{青} {用のscanf} $
cin>>n>>q;
for(int i=1;i<=q;i++)
{
cin>>qx[i]>>qy[i];
char c=getchar();
if(c==' ')
{
cin>>qw[i];
add_edge(qx[i],qy[i],qw[i]);
add_edge(qy[i],qx[i],qw[i]);
}
else
qw[i]=-1;
}
for(u=1;u<=n;u++)
if(fa[u][0]==0)
dfs(u);
for(k=1;k<=20;k++)
for(int u=1;u<=n;u++)
{
int v=fa[u][k-1];
fa[u][k]=fa[v][k-1];
g[u][k]=g[v][k-1]+g[u][k-1];
}
for(i=1;i<=q;i++)
{
int u=qx[i];
int v=qy[i];
if(qw[i]==-1)
{
if(find(u)==find[v])
cout<<path(u,v)<<endl;
else
cout<<-1<<endl;
}
else
p[find[u]]=find[v];
}
void dfs(int u)
{
d[u]=d[fa[u][0]]+1;
for(int i=head[u];i;i=e[i].next)
{
v=e[i].to;
if(v!=fa[u][0])
{
g[v][0]=e[i].val;
fa[v][0]=u;
dfs(v);
}
}
}
int path(int u,int v)
{
int sum=0;
if(d[u]<d[v])
return path(v,u);
for(int k=20;k>=0;k--)
{
int uu=fa[u][k];
if(d[uu]>=d[v])
{
sum+=g[u][k];
u=uu;
}
}
if(u==v)
return sum;
for(int k=20;k>=0;k--)
{
int uu=fa[u][k];
int vv=fa[u][k];
if(vv!=uu)
{
sum+=g[u][k];
sum+=g[v][k];
u=uu;
v=vv;
}
}
return sum+g[u][0]+g[v][0];
}