[THOJ 1595] sup

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[THOJ 1595] sup相关的知识,希望对你有一定的参考价值。

题意

  给定一棵以 1 为根的树.

  多组询问, 每次给定 K , 每次选择不超过 K 个已被删除的节点删除, 问最少多少次才能清空.

  n, K <= 1000000 .

 

分析

  神题.

  考虑数形结合.

  设 f[x] 为深度 >= x 的个数, f[x] 单调递减.

  对二维平面上的点 (x, f[x]) 构建上凸壳.

  依次预处理 1, 2, ..., H 的答案, 找到切线.

  可以证明, 对于切点左边, 需要深度次, 对于切点右边, 每次可以删 K 个.

 

实现

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
using namespace std;
#define F(i, a, b) for (register int i = (a); i <= (b); i++)
#define D(i, a, b) for (register int i = (a); i >= (b); i--)
#define LL long long
inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
}

const int N = 1000005;

int n, qs[N], par[N];
int dep[N], f[N], Max;
int s[N], Len, ans[N];
inline LL det(int x, int y, int _x, int _y) { return 1LL * x * _y - 1LL * y * _x; }

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("sup.in", "r", stdin);
    #endif
    
    n = rd(), qs[0] = rd();
    F(i, 1, qs[0]) qs[i] = rd();
    F(i, 2, n) par[i] = rd();
    
    dep[1] = 1;
    F(i, 2, n) dep[i] = dep[par[i]] + 1;
    F(i, 1, n) f[dep[i]]++;
    D(i, n, 1) f[i] += f[i+1];
    Max = *max_element(dep+1, dep+n+1);

    F(i, 1, Max+1) {
        while (Len >= 2 && det(i - s[Len-1], f[i] - f[s[Len-1]], s[Len] - s[Len-1], f[s[Len]] - f[s[Len-1]]) < 0)
            s[Len--] = 0;
        s[++Len] = i;
    }
    for (int K = 1, cur = 1; K <= n; K++) {
        while (cur+1 <= Len && det(1, -K, s[cur+1] - s[cur], f[s[cur+1]] - f[s[cur]]) >= 0)
            cur++;
        ans[K] = s[cur]-1 + (f[s[cur]]+K-1) / K;
    }
    F(i, 1, qs[0])
        printf("%d ", qs[i] <= n ? ans[qs[i]] : Max);
    puts("");
    
    return 0;
}

 

以上是关于[THOJ 1595] sup的主要内容,如果未能解决你的问题,请参考以下文章

[THOJ 2175] cut

[THOJ 1596] 旅行

拥有的50个CSS代码片段(上)

[THOJ 1587] 小方格

[THOJ 1601] 消防站

[THOJ 1589] 椭球面 三分套三分