zoukankan      html  css  js  c++  java
  • 【BZOJ】3835: [Poi2014]Supercomputer

    题意

    (n(1 le 1000000))个点的有根树,(1)号点为根,(q(1 le 1000000))次询问,每次给一个(k),每一次可以选择(k)个未访问的点,且父亲是访问过的,要求最少次数访问完所有的点。

    分析

    神题不会做。

    题解

    得到一个式子(ans=max(i+ left lceil frac{s[i]}{k} ight ceil), 0 le i le maxh),其中(maxh)是最大深度,(s[i])是深度大于(i)的点的数量。证明如下:
    定义关键层(i)表示拿了(i)次后、前(i)层已经拿完,以后每一次都可以拿(k)个(最后一次除外)。我们需要证明:1、存在关键层。2、关键层的解是最小解。
    首先我们按照下面两个规则查询:

    1. 如果当前层(i)的结点不够(k),则查询完,而且如果之前有(j < i)层的点没查询,则查询完。
    2. 如果足够了(k),则在保证最终能在第(maxh)次遍历到第(maxh)层的情况下,随便选(k)个。

    那么显然在最后一个执行1操作而且那层(i)不存在(j < i)层的点没查询的(i)就是关键层。由于这样的1操作至少有一个(即第1层肯定是执行的是这样的1操作),所以关键层肯定存在,而且只有一个。
    至于关键层的解是否是最小解,感觉很显然,然而不会严格证明。
    至于取max,不会严格证明。

    最后原题可以转化为(ans=left lceil max(i+frac{s[i]}{k}) ight ceil),所以按照(i+frac{s[i]}{k})来斜率优化就行辣。

    #include <bits/stdc++.h>
    using namespace std;
    inline int getint() {
    	int x=0;
    	char c=getchar();
    	for(; c<'0'||c>'9'; c=getchar());
    	for(; c>='0'&&c<='9'; x=x*10+c-'0', c=getchar());
    	return x;
    }
    typedef long long ll;
    const int N=1000005;
    int a[N], d[N], q[N], c[N], ihead[N], cnt;
    struct E {
    	int next, to;
    }e[N];
    void add(int x, int y) {
    	e[++cnt]=(E){ihead[x], y}; ihead[x]=cnt;
    }
    void dfs(int x) {
    	for(int i=ihead[x]; i; i=e[i].next) {
    		d[e[i].to]=d[x]+1;
    		dfs(e[i].to);
    	}
    }
    inline bool ok1(int i, int j, int k) {
    	return (ll)(c[j]-c[i])*(k-i)>(ll)(c[k]-c[i])*(j-i);
    }
    inline bool ok2(int b, int j, int k) {
    	return (ll)b*(j-k)>c[k]-c[j];
    }
    int main() {
    	int n=getint(), Q=getint();
    	for(int i=0; i<Q; ++i) {
    		a[i]=getint();
    	}
    	d[0]=1;
    	int mx=1;
    	for(int i=1; i<n; ++i) {
    		add(getint()-1, i);
    	}
    	dfs(0);
    	for(int i=0; i<n; ++i) {
    		++c[d[i]-1];
    		mx=max(mx, d[i]);
    	}
    	for(int i=mx; i; --i) {
    		c[i]+=c[i+1];
    	}
    	int *fr=q+1, *ta=q;
    	for(int i=1; i<=mx; ++i) {
    		for(; fr<ta && ok1(*(ta-1), i, *ta); --ta);
    		*++ta=i;
    	}
    	for(int i=1; i<=n; ++i) {
    		for(; fr<ta && ok2(i, *(fr+1), *fr); ++fr);
    		d[i]=*fr+(c[*fr]+i-1)/i;
    	}
    	for(int i=0; i<Q; ++i) {
    		printf("%d%c", a[i]>n?mx:d[a[i]], " 
    "[i==Q-1]);
    	}
    	return 0;
    }
  • 相关阅读:
    在SpringBoot中使用JWT
    异常解决:non-compatible bean definition of same name and class【com.xxx.xxx.XXX】
    mysql 字段名和关键字冲突
    约束(主键、非空、唯一性、外键、检查约束)
    唯一索引与非唯一索引区别(UNIQUE INDEX, NON-UNIQUE INDEX)
    数据库设计mysql字段不默认为NULL原因搜集
    mysql索引总结----mysql 索引类型以及创建
    互联网数据库架构设计思路
    干货满满!10分钟看懂Docker和K8S
    PowerDesigner 使用教程(很具体,很实用)
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4986048.html
Copyright © 2011-2022 走看看