1.变异蛮牛
很显然要求的就是以一为起点到以一为终点的个数,对于一个节点分析,我们可以发现它的贡献可以分为:
1.若该节点为黑的时候,可以与子节点为黑的节点相连,并且子节点之间也可以相连
2.若该节点为白的时候,并且子节点之间也可以相连
利用递归的思想,先处理每个节点中的黑点个数,再分类计数即可。(复杂度O(n))
#include<bits/stdc++.h>
using namespace std;
int t;
int n;
const int N = 2e5 + 10, M = 2 * N;
int st[N];
int h[N],e[M],ne[M],idx;
int c[N];
int sz[N];
long long ans = 0;
void add (int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
void dfs1(int u,int fa,int color)
{
c[u] = color;
if(c[u] == 1) sz[u]++;
for(int i = h[u] ; i != -1 ; i = ne[i])
{
int j =e[i];
if(j == fa) continue;
dfs1(j,u,color^1);
sz[u] += sz[j];
}
}
int an[N];
void dfs2(int u,int fa)
{
int tmp = 0;
for(int i = h[u] ; i != -1 ; i = ne[i])
{
int j =e[i];
if(j == fa) continue;
dfs2(j,u);
an[u] += sz[j] * tmp;
tmp +=sz[j];
}
if(c[u] == 1) an[u]+= tmp + 1;
ans +=an[u];
}
int main()
{
cin >> t;
while(t--)
{
cin >> n;
idx = 0;
for(int i = 1; i <= n; i++) {
h[i] = -1;
ans =0;
sz[i] = 0;
an[i] = 0;
}
int x,y;
for(int i = 1 ; i < n ; i++)
{
cin >> x >> y;
add(x,y);
add(y,x);
}
dfs1(1,0,1);
dfs2(1,0);
cout << ans << endl;
}
return 0;
}
2.树上子链
树上直径板子题,只不过点权改为了边权。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 10, M = 2 * N;
ll ans = -0x3f3f3f3f;
int n, k;
ll d[N];
bool st[N];
int h[N],e[M],ne[M],idx;
ll a[N];
ll dp[N];
void add (int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
void dfs(int u,int fa)
{
dp[u] = a[u];
ans = max(dp[u],ans);
for(int i = h[u]; i != - 1 ; i = ne[i])
{
int j = e[i];
if(j == fa) continue;
dfs(j,u);
ans = max(ans,dp[u] + dp[j] ); //最长链与次长链
dp[u]=max(dp[u],dp[j]+a[u]);//最长链更新
}
}
int main()
{
cin >> n;
memset(h,-1,sizeof h);
ll maxx = -0x3f3f3f3f;
for(int i = 1 ; i <= n ; i++) cin >> a[i];
int x,y;
for(int i = 1 ; i < n ; i++)
{
cin >> x >> y;
add(x,y);
add(y,x);
}
dfs(1,0);
cout << ans;
}