タイトル
[問題の説明]
Hjaが持っている\(N \)ツリー点、各点ツリーの少し右に、各エッジの色は、重量パスが正しいと点が、この経路上の全ての点への正当なパスが満たす必要があります任意の2つの隣接する辺上のパスは、同じ色ではない。全ての重みを依頼し、このツリーの正当な経路です。
[入力形式]
最初の行番号\(\ N-) 。
次の行の\(N- \)の各点の値の数値表現。
次\(N-1 \)各行三列整数\(U \ V \ C \) 、代表\(U \)する(Vを\)は\の間の色有する\(C \)エッジ。
[出力形式]
整数ラインは答えを表しています。
[サンプル入力]
6
6 2 3 7 1 4
1 2 1
1 3 2
1 4 3
2 5 1
2 6 2
[サンプル出力]
134
データ範囲の[規則]
\(1 \ルN \ル
3 \回10 ^ 5,1 \ルC \ル10 ^ 9 \) 答えが以下であることを確実にする\(2 ^ {63} -1 \) 。
アイデア1 \(O(N ^ 2)\)暴力
一度、DFSは、すべての正当なパスと重量の終点までの各点から計算される。各鎖は二回計算される、ことが答え\(/ 2 \) 。
時間複雑\(O(N ^ 2) \)
#include<bits/stdc++.h>
#define LL long long
const int SIZE=300005;
int n,head[SIZE],nex[SIZE*2],to[SIZE*2],edge[SIZE*2],Tot;
LL weight[SIZE],Ans;
void Link(int u,int v,int e)
{
nex[++Tot]=head[u];head[u]=Tot;to[Tot]=v;edge[Tot]=e;
nex[++Tot]=head[v];head[v]=Tot;to[Tot]=u;edge[Tot]=e;
}
void DFS(int u,int F,LL sum,int Las)
{
Ans+=sum;
for(int i=head[u];i;i=nex[i])
{
int v=to[i];
if(v==F||edge[i]==Las)continue;//不能出现连续两条颜色相同的边
DFS(v,u,sum+weight[v],edge[i]);
}
}
int main()
{
int u,v,e;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&weight[i]);
Ans-=weight[i];
}
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&e);
Link(u,v,e);
}
for(int i=1;i<=n;i++)DFS(i,0,weight[i],0);
printf("%lld",Ans/2);
return 0;
}
アイデア2 \(O(N)\)メモリ検索
見つけるのは簡単、重複した状態の多数の検索のアイデア。
たとえば、
今、私たちは、黒く塗りつぶされた点から検索開始でピンク色のボックスで見つけた四つの状態、右に記載されているが、。
それは状態があることに留意すべきである(パウダーブルーボックスの左下隅の連続する2つの側面が)正当ではない、我々は、この状態を維持していません。
今、私たちは第二の点DFSを変更、上の図取ったブラックアウトポイントをその例に。
検索を開始するには、この点から、まだピンク色の箱に入ります、ピンクのボックスはまだ右に記載されているこれらの4つの状態の発作、になります。
唯一の緑色のボックスでは本質的に同じ、異なるのポイントに、これら四つの状態や状態を見つけるのは簡単。
換言すれば、これらの四つの状態の粉末ボックスの部分には同じです。
これは、ということを教えてくれるピンクボックスは状態が見つけたボックス内の次の直接呼び出し、もはやDFS粉末を保存します。
これは次のとおりです。
我々が検索するときのポイントを黒くしたときに、検索する粉末ボックスに行かなくても状態から直接粉末ボックスを、答えを参加しました。
見つけやすい、状態がされなければならない(有向)エッジに格納され、そしてこのメモリは、すべての側面に一般化することができます。
だから我々は、検索のコードメモリを得ました。
#include<bits/stdc++.h>
#define LL long long
const int SIZE=600005;
int n,head[SIZE],nex[SIZE],to[SIZE],edge[SIZE],Tot;
LL weight[SIZE],Ans;
void Link(int u,int v,int e)
{
nex[++Tot]=head[u];head[u]=Tot;to[Tot]=v;edge[Tot]=e;
nex[++Tot]=head[v];head[v]=Tot;to[Tot]=u;edge[Tot]=e;
}
struct Re{LL Res;int w;}x[SIZE];
Re DFS(int u,int F,LL sum,int Las)
{
Re R=(Re){sum,1};
for(int i=head[u];i;i=nex[i])
{
int v=to[i];
if(v==F||edge[i]==Las)continue;
if(x[i].w)R=(Re){R.Res+x[i].w*sum+x[i].Res,R.w+x[i].w};//遍历过,直接取出,不再继续往下搜索
else
{
Re Tem=DFS(v,u,sum+weight[v],edge[i]);//没遍历过,继续搜索
R=(Re){R.Res+Tem.Res,R.w+Tem.w};
x[i]=(Re){Tem.Res-sum*x[i].w,Tem.w};//记下状态
}
}
return R;
}
int main()
{
int u,v,e;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&weight[i]);
Ans-=weight[i];
}
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&e);
Link(u,v,e);
}
for(int i=1;i<=n;i++)
Ans+=DFS(i,0,weight[i],0).Res;
printf("%lld",Ans/2);
return 0;
}
明らかに、各エッジは、一度だけの時間複雑さの横断\を(O(N)\) 。