タイトル
質問の意味:
加重ツリー、0または1の重さを考えます。必要なポイントの数は(x、y)の私の条件を満たすように決定されます。XからYへの条件は、1重量後のパスに存在し、その後縁の右側を通ってゼロでなくてもよいです。
分析:
分析後、ポイントは、0にすべて0または1再度、全体パス1のいずれかのため、条件を満たすことです。だから我々は、染色された通信ブロック0、右用通信ブロックの側面と1の右側だけを求めて行くことができます。染色した後、すべてゼロとすべてのものは容易に計算することができます。1次に0最初のために、我々は、ブロック0で通信する権利、および通信ブロック1のための右側の側で、2つの通信部01が、このことによってそれに接続することができ、両方の、ポイントの数を考えます答えが形成され、すなわち、図1に示すように、0が最初に後に計算されていることをこの時点でメモを除外する。
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
struct node{
int num,val;
node(int a,int b)
{
num = a;
val = b;
}
};
vector<node> g[200005];
int color1[200005],color2[200005],size1[200005],size2[200005];
int c1 = 1,c2 = 1;
void dfs1(int x,int fa)
{
if( color1[fa] == 0 && fa != 0 )
{
color1[fa] = c1;
size1[c1] ++;
}
for (int i = 0; i < g[x].size(); i++)
{
node t = g[x][i];
if( color1[t.num] ) continue;
if( t.val == 1 )
{
dfs1(t.num,x);
}
}
if( color1[x] == 0 && fa != 0 )
{
color1[x] = c1;
size1[c1] ++;
}
}
void dfs2(int x,int fa)
{
if( color2[fa] == 0 && fa != 0 )
{
color2[fa] = c2;
size2[c2] ++;
}
for (int i = 0; i < g[x].size(); i++)
{
node t = g[x][i];
if( color2[t.num] ) continue;
if( t.val == 0 )
{
dfs2(t.num,x);
}
}
if( color2[x] == 0 && fa != 0 )
{
color2[x] = c2;
size2[c2] ++;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for (int i = 1; i < n; i++)
{
int x,y,v;
cin >> x >> y >> v;
g[x].push_back(node(y,v));
g[y].push_back(node(x,v));
}
for (int i = 1; i <= n; i++)
{
if( color1[i] == 0 )
{
dfs1(i,0);
if( size1[c1] > 0 ) c1 ++;
}
if( color2[i] == 0 )
{
dfs2(i,0);
if( size2[c2] > 0 ) c2 ++;
}
}
ll ans = 0;
//cout << c1 << ' ' << size1[c1-1] << ' ' << c2 << ' ' << size2[c2-1] << '\n';
for (int i = 1; i < c1; i++)
{
ans += (ll)( size1[i] - 1 ) * size1[i];
}
for (int i = 1; i < c2; i++)
{
ans += (ll)( size2[i] - 1 ) * size2[i];
}
for (int i = 1; i <= n; i++)
{
if( color1[i] != 0 && color2[i] != 0 )
{
ans += (ll)(size2[color2[i]] - 1) * ( size1[color1[i]] - 1 );
}
}
cout << ans << '\n';
return 0;
}