Godfather
const int N = 500010;
int h[N], e[N], ne[N], idx;
bool vis[N];
vector<PII>ans;//second是点的编号,first是划去这个点后剩下最大连通块的大小是多少
int n,root;
int d[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int dfs(int u)
{
vis[u] = true;//sum是以当前u为根节点的子树大小,anss是划掉u这个节点后剩下连通块的最大值
int sum = 1, anss = 0;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (!vis[j])
{
int s = dfs(j);
anss = max(s, anss);
sum += s;
}
}
anss = max(anss, n - sum);
ans.push_back(make_pair(anss, u));
return sum;
}
int main()
{
n = read();
memset(h, -1, sizeof h);
for (int i = 0; i < n - 1; i++)
{
int a, b;
a = read(), b = read();
add(a, b), add(b, a);
d[b]++;
}
for(int i=1;i<=n;i++)
if (!d[i])
{
root = i;
break;
}
dfs(root);
sort(ans.begin(), ans.end());//按划掉这个点后剩下最大连通块大小从小到大排序
int i = 0;
while (1)//打印答案直到不同就退出
{
cout << ans[i].second<<" ";
if (ans[i].first != ans[i + 1].first)break;
i++;
}
}
Cow Marathon
const int N = 50010, M = 250000;
int h[N], e[M], ne[M], w[M], idx;
int d[N];
bool vis[N];
int n, m;
int root;
int dp[N];//dp[i]即i这个点到它的子树上最远的点的距离是多少
int ans;
void dfs(int x)
{
vis[x] = 1;
for (int i = h[x]; ~i; i = ne[i])
{
int j = e[i];
if (!vis[j])
{
dfs(j);//先dfs再做后续操作
ans = max(ans, dp[x]+dp[j]+w[i]);//先让ans取max再更新dp[x]就可以避免ans中计算的dp[x]和dp[j]在同一条路径上的情况;
dp[x] = max(dp[x], dp[j] + w[i]);
}
}
}
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int main()
{
n = read(), m = read();
memset(h, -1, sizeof h);
while (m--)
{
int a, b, c;
a = read(), b = read(), c = read();
add(a, b, c), add(b, a, c);
d[b]++;
}
for (int i = 1; i <= n; i++)
{
if (!d[i])
{
root = i;
break;
}
}
dfs(root);
cout << ans;
}
Farthest tree node in tree (2)
const int N = 30010, M = 60010;
int h[N], e[M], ne[M], w[M], idx;
int d[N];
bool vis[N];
int n;
int root;
int dp[N][3];//0是到子树的最远点的距离,1是到子树的次远点的距离,2是到除子树外(即往上)的最远点距离
void dfs1(int x)
{
vis[x] = 1;
for (int i = h[x]; ~i; i = ne[i])
{
int j = e[i];
if (!vis[j])
{
dfs1(j);//先递归再做其他操作
if (dp[j][0] + w[i] >= dp[x][0])//更新到子树的最大值和次大值
{
dp[x][1] = dp[x][0];
dp[x][0] = dp[j][0] + w[i];
}
else if (dp[j][0] + w[i] >= dp[x][1])
dp[x][1] = dp[j][0] + w[i];
}
}
}
void dfs2(int x)
{
vis[x] = 1;
for (int i = h[x]; ~i; i = ne[i])
{
int j = e[i];
if (!vis[j])
{
if (w[i] + dp[j][0] == dp[x][0])//说明父亲节点的往子树最大值和本节点往子树最大值处在同一路径上,所以只能使用次大值让其不在同一路径上
dp[j][2] = max(dp[x][2] + w[i], dp[x][1] + w[i]);
else dp[j][2] = max(dp[x][2] + w[i], dp[x][0] + w[i]);
dfs2(j);//先做完其他操作再递归
}
}
}
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int main()
{
int t; t = read();
int cnt = 1;
while (t--)
{
printf("Case %d:\n", cnt++);
n = read();
memset(h, -1, sizeof h),idx=0;
memset(d, 0, sizeof d);
memset(dp, 0, sizeof dp);
memset(vis, 0, sizeof vis);
for (int i = 0; i < n - 1; i++)
{
int a, b, c;
a = read(), b = read(), c = read();
add(a, b, c), add(b, a, c);
d[b]++;
}
for (int i = 0; i < n; i++)
{
if (!d[i])
{
root = i;
break;
}
}
dfs1(root);
memset(vis, 0, sizeof vis);
dfs2(root);
for (int i = 0; i < n; i++)cout << max(dp[i][2],dp[i][0]) << endl;
}
}
Masha and a Beautiful Tree
玛莎认为,如果树叶中的值按照从左到右的递增顺序排列,那么这棵树就很美。在一个操作中,Masha可以选择树的任何非叶顶点,并交换它的左右子结点(以及它们的子树)。
帮助玛莎了解她是否可以在一定数量的操作中使一棵树变得美丽。如果可以,那么输出最小数量的操作,使树变得漂亮。
思路:分治递归模拟二叉树的替换
int s[262190];
int ans;
void dfs(int l, int r)
{
if (l >= r)return;//递归出口;(l==r是叶子节点)
int mid = l + r >> 1;
dfs(l, mid), dfs(mid + 1, r);//先递归左右子树再执行后续操作,则达到从下往上处理树的效果;
if (s[l] > s[r])//当前树的左端点>右端点则一定需要依次交换两个子树
{
ans++;
for (int i = l; i <= mid; i++)//模拟两个子树的交换
swap(s[i], s[i + mid + 1 - l]);//mid+1-l就是一个子树的长度,则i+这个长度就能得到左子树的点对应到右子树是哪一个点
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
ans = 0;
int n; cin >> n;
for (int i = 1; i <= n; i++)scanf("%d", &s[i]);
dfs(1, n);
int i;
for ( i = 1; i < n; i++)//dfs完后循环一遍,若叶子节点仍未排好序则说明不可能使得!
if (s[i] > s[i + 1])
{
cout << "-1" << endl;
break;
}
if (i == n)cout << ans << endl;
}
}