感觉考场上不一定做得出来的题目?
首先我们可以得到每个点的深度,然后猜测这个只和每个层的深度有关。
我们考虑这样一个贪心:对于每一层的每个点,如果这个点有子节点,那么优先搞这个点,否则先放一放,这样可以保证如果点数足够,那么能操作的点数是递增的,如果操作的点数不递增,那么显然无论什么操作都最优只能做到这样。
则我们统计出当前层的的点数,并设\(f_i\)为操作到第\(i\)步的时候最少能剩下的点数,则\(f_i=\max(f_{i-1}+q_i-k,0)\)。可以做到\(O(nq)\)。
实际上可以发现是一条斜线截凸包的形式,则可以斜率优化,时间复杂度\(O(n+q)\)
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=1e6+5,M=pow(6,10)+5,K=2e3+5,mod=998244353,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int n,m,k,x,y,z,Mx,d[N],A[N],Fl[N],Ct,ToT,st[N],sh,H,Ans[N];
db slope(int x,int y){return (Fl[y]-Fl[x])*1.0/(y-x);}
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d",&n,&m);for(i=1;i<=m;i++)scanf("%d",&A[i]);d[1]=1;for(i=2;i<=n;i++) scanf("%d",&x),d[i]=d[x]+1,Fl[d[i]]++,Mx=max(Mx,d[i]);
Fl[1]=1;for(i=1;i<=Mx;i++) Fl[i]+=Fl[i-1];for(i=1;i<=Mx;i++) {while(sh>1&&slope(st[sh-1],st[sh])>slope(st[sh],i)) sh--;st[++sh]=i;}
H=1;for(i=1;i<=n;i++){while(H^sh&&slope(st[H],st[H+1])<i) H++;Ans[i]=Fl[st[H]]+1ll*(Mx-st[H])*i;}for(i=1;i<=m;i++) printf("%d ",(n-Ans[min(A[i],n)]+A[i]-1)/A[i]+Mx);
}
标签:int,luogu,Supercomputer,st,sh,点数,using,P3571,define
From: https://www.cnblogs.com/275307894a/p/16756196.html