C. News Distribution(1400)(并查集求连通块点的个数)
分析:给定n,m,n表示n个用户,m表示组数,每组有很多人。我们可以通过并查集求连通块内的点的个数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 500005;
int p[N];
int sz[N];
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) p[i] = i, sz[i] = 1;
for (int i = 1; i <= m; ++i)
{
int k;
scanf("%d", &k);
if (k == 0)
continue;
else
{
int last;
scanf("%d", &last);
if (k >= 2)
{
int d;
for (int j = 2; j <= k; ++j)
{
scanf("%d", &d);
int pa = find(last), pb = find(d);
if (pa != pb)
{
p[pa] = pb;
sz[pb] += sz[pa];
}
last = d;
}
}
}
}
for (int i = 1; i <= n; ++i)
{
int f = find(i);
printf("%d ", sz[f]);
}
//
return 0;
}
A. Sum in the tree(DFS)(贪心)
分析:偶数层为-1,偶数层的s应该最大为所有子结点s的最小值,然后还要考虑叶子节点为偶数层的时候,直接赋值父节点的s。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
using LL = long long;
const int N = 200005;
const int INF = 0x3f3f3f3f;
int h[N], e[N * 2], ne[N * 2], idx;
int s[N];
bool flag;
LL ans;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int fa)
{
if (s[u] == -1)//偶数层
{
LL mn = 0x3f3f3f3f;
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (j == fa) continue;
mn = min(mn, (long long)s[j]);
}
s[u] = mn;
}
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (j == fa) continue;
dfs(j, u);
if (s[j] == 0x3f3f3f3f)
s[j] = s[u];
}
}
void dfs_2(int u, int father)
{
if(flag) return;
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (j != father)
{
LL t = s[j] - s[u];
if (t < 0)
{
flag = true;
return;
}
ans += t;
dfs_2(j, u);
}
}
}
int main()
{
int n;
scanf("%d", &n);
memset(h, -1, sizeof h);
int p;
for (int i = 2; i <= n; ++i)
{
scanf("%d", &p);
add(i, p), add(p, i);
}
for (int i = 1; i <= n; ++i)
{
scanf("%d", &s[i]);
}
dfs(1, -1);
dfs_2(1, -1);
if (flag)
{
puts("-1");
}
else
{
printf("%lld
", ans + s[1]);
}
return 0;
}