2020牛客多校第四场A题
题意:
给一个有根树,在树上选择 k 个关键点(根必须选)
最小化点到最近关键祖先距离的最大值
求出 k 分别为 1,2,…,n 时答案的和
思路:
对于我们要求某个答案下的最少需求,可以知道对于一个点,如果不是取的最后一个点,都可以取至少个点,除去本身以外个点。于是乎,我们可以看到对于关键点个数有的时候,答案个数大概会在左右,那么,这里岂不是有一个类似于整数除法,那么,可以推测不同的关键点个数,可能答案是会相同的,所以我们不妨去处理出表示答案为i时候,所使用的关键点的最多个数,那么就可以知道答案为i时候的种类数了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
namespace fastIO {
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline bool read(int &x) {
char ch;
while(blank(ch = nc()));
if(IOerror) return false;
for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
return true;
}
#undef BUF_SIZE
};
using namespace fastIO;
const int maxN = 2e5 + 7;
int N, head[maxN], cnt, fa[maxN], deep[maxN], dfn[maxN], rid[maxN], tot, end_tim[maxN], max_deep;
vector<int> leave;
bool cmp(int e1, int e2) { return deep[e1] > deep[e2]; }
bool cmp_rid(int e1, int e2) { return deep[rid[e1]] > deep[rid[e2]]; }
struct Eddge
{
int nex, to;
Eddge(int a=-1, int b=0):nex(a), to(b) {}
} edge[maxN];
inline void addEddge(int u, int v)
{
edge[cnt] = Eddge(head[u], v);
head[u] = cnt++;
}
void dfs(int u)
{
dfn[u] = ++tot; rid[tot] = u;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
deep[v] = deep[u] + 1; max_deep = max(max_deep, deep[v]);
dfs(v);
}
if(!~head[u]) leave.push_back(u);
end_tim[u] = tot;
}
int ans[maxN], cop[maxN];
void cdq(int lenL, int lenR, int l, int r)
{
if(lenL > lenR || l > r) return;
if(l == r)
{
for(int i=lenL; i<=lenR; i++) ans[i] = l;
return;
}
int mid = (lenL + lenR) >> 1;
ans[mid] = 0;
for(int i=1; i<=N; i++) cop[i] = deep[i];
for(int i=N, u; i>=1; i--)
{
u = rid[i];
if(cop[u] == deep[u] + mid || u == 1)
{
ans[mid]++;
cop[u] = -1;
}
cop[fa[u]] = max(cop[fa[u]], cop[u]);
}
cdq(lenL, mid - 1, ans[mid], r);
cdq(mid + 1, lenR, l, ans[mid]);
}
inline void init()
{
cnt = max_deep = tot = 0;
for(int i=1; i<=N; i++) { head[i] = -1; leave.clear(); }
}
int main()
{
while(read(N))
{
init();
for(int i=2; i<=N; i++) { read(fa[i]); addEddge(fa[i], i); }
deep[1] = 0;
dfs(1);
cdq(0, max_deep, 1, N);
int sum = 0;
for(int i=1; i<=max_deep; i++) sum += i * (ans[i - 1] - ans[i]);
printf("%d\n", sum);
}
return 0;
}