[ 杂题 复杂度分析 ] Codeforces955F Heaps

对于 k=1 k = 1 ,可以直接树形DP求出答案。
对于 k>1 k > 1 ,显然 maxdepth<logkn m a x d e p t h < log k ⁡ n 。设 dpi,j d p i , j 表示 i i 号点, depth d e p t h j j 时最大的 k k ,那么状态数是 O(nlogn) O ( n log ⁡ n ) 的。
如果我们求出了 dpi,j d p i , j ,由于随着 k k 的减小,每个点的 depth d e p t h 肯定是单调不降的,所以可以把每个 k k 要更新哪些点记下来,从大到小枚举 k k ,更新相关点的 depth d e p t h 。由于一个点最多只会被更新 maxdepth m a x d e p t h 次,这部分的复杂度为 O(nlogn) O ( n log ⁡ n )
然后考虑怎么求 dpx,i d p x , i 。将所有儿子按照 dpv,i1 d p v , i − 1 从大到小排序,如果第 k k 大的值 k ≥ k dpx,i d p x , i 就可以取到 k k 。从大到小枚举 k k ,找到就退出。复杂度为 nni=2login=O(nlogn) n ∑ i = 2 n log i ⁡ n = O ( n log ⁡ n )

#include
using namespace std;
char nc() {
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
void Read(int& x) {
    char c=nc();
    for(;c<'0'||c>'9';c=nc());
    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
#define fi first
#define se second
const int N=300010;
const int M=19;
typedef pair<int,int> abcd;
typedef long long ll;
int n,m,x,y;
int t[N<<1],nx[N<<1],h[N],num;
int f[N],c[N],dp[N][M];
int a[N],l,cur[N];
vector g[N];
ll Res,Ans;
void Add(int x,int y) {
    t[++num]=y;nx[num]=h[x];h[x]=num;
}
bool Cmp(int x,int y) {
    return x>y;
}
void Dfs(int x,int y) {
    dp[x][1]=n;f[x]=y;
    for(int i=h[x];i;i=nx[i])
        if(t[i]!=y) Dfs(t[i],x),c[x]=max(c[x],c[t[i]]);
    for(int j=2;j0;
        for(int i=h[x];i;i=nx[i])
            if(t[i]!=y&&dp[t[i]][j-1]) a[++l]=dp[t[i]][j-1];
        sort(a+1,a+l+1,Cmp);
        for(int k=l;k>1;k--)
            if(a[k]>=k) {
                dp[x][j]=k;
                break;
            }
        if(dp[x][j]) g[dp[x][j]].push_back(abcd(x,j));
    }
    Ans+=++c[x];
}
void Update(int x,int y) {
    while(x) {
        if(cur[x]>=y) break;
        Res+=y-cur[x];
        cur[x]=y;
        x=f[x];
    }
}
int main() {
    Read(n);
    for(int i=1;i1,0);
    for(int i=1;i<=n;i++) cur[i]=1;
    Res=n;
    for(int k=n;k>1;k--) {
        for(int j=0;jcout<return 0;
}

你可能感兴趣的:(杂题,复杂度分析)