集训day3 t1 Tree(CF300 E)
Tree
【题目描述】
RHL有一天看到lmc在玩一个游戏。
“愚蠢的人类哟,what are you doing”,RHL说。
“我在玩一个游戏。现在这里有一个有n个结点的有根树,其中有m个叶子结点。这m个叶子从1到m分别被给予了一个号码,每个叶子的号码都是独一无二的。一开始根节点有一个棋子,两个玩家每次行动将棋子移动到当前节点的一个儿子节点。当棋子被移动到某个叶节点的时候游戏结束,这个叶节点的号码即为该局游戏的result。先手的玩家要最大化result,后手的玩家要最小化这个result。”
“你不先问一下我是谁吗 = =”
“那么,who are you”
“我是这个世界的创造者,维护者和毁灭者,整个宇宙的主宰,无所不知,无所不能的,三个字母都大写的RHL。”
“既然你这么厉害,那你一定知道,在两个玩家都无限聪明的情况下,在树的形态已知的情况下,在叶子的编号可以任意安排的情况下,游戏的result最大是多少咯。”
【输入格式】
输入数据第一行有一个正整数n,表示结点的数量。
接下来n-1行,每行有两个正整数u和v,表示的父亲节点是u。
【输出格式】
输出一行2个非负整数,分别表示result的最大值和最小值。
【样例输入】
5
1 2
1 3
2 4
2 5
【样例输出】
3 2
【样例解释】
有3,4,5三个叶子。若令3号叶子的编号是3,则先手可以移到3号结点,故result最大是3。若3号叶子的编号是2,则先手可以移到3号结点,故result最小是2.
【数据范围】
30%,n<=10
100%,n<=200000
今天垫底了。。。。。
一开始看错题,以为不用自己安排编号,于是写了个默认点节点编号的,大概就是每个点记录一个先手最大和后手最大,然后节点的先手最大等于子节点的后手的最大值,后手的等于子节点先手的最小值,想一想很显然吧。。。。然后叶子节点的两个值等于编号。。。。。。然后发现这要自己对子节点编号。。。。。然后就SB地顺着思路去枚举编号,然后就只有30分。
正解 每个点存这个点能够到达的最大的是这个点的子树的叶节点中第几大的点,记a1,最小的是第几小的点b1,叶节点显然都是1,都记先手的,于是父节点(假设为2)的a2=min(b1),b2=sum(a1) (妈蛋,我不会说了,貌似没理解。。。)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int INF=100000000;
int n,xs[200006],hs[200006];
vector<int> g[200005];
int m=0;//xs第几大 hs第几小
void dfs(int x)
{
if (!g[x].size())
{
xs[x]=1;
hs[x]=1;
m++;
return ;
}
xs[x]=INF;
hs[x]=0;
for (int i=0;i<g[x].size();i++)
{
dfs(g[x][i]);
xs[x]=min(xs[x],hs[g[x][i]]);
hs[x]+=xs[g[x][i]];
}
return ;
}
int main()
{
scanf("%d",&n);
int x,y;
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
}
dfs(1);
printf("%d %d\n",m-xs[1]+1,hs[1]);
return 0;
}