平衡树性质+思维——NWERC 2019 Balanced Cut

找了老半天错误。。

高度为i的平衡树至少要有f(i)=f(i-1)+f(i-2)+1个结点
从小到达枚举i,如果i被选中,那么其所有祖先p也必被选中
考虑i能否加入:如果i在祖先p的左子树里,p的左子树高度更新,连带更新右子树必须要有的高度
如果i在组先p的右子树里,更新右子树高度,只要右子树高度<=左子树高度+1即可

/*
高度为i的平衡树至少要有f(i)=f(i-1)+f(i-2)+1个结点
从小到达枚举i,如果i被选中,那么其所有祖先p也必被选中
考虑i能否加入:如果i在祖先p的左子树里,p的左子树高度更新,连带更新右子树必须要有的高度
          如果i在组先p的右子树里,更新右子树高度,只要右子树高度<=左子树高度+1即可 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 600005

int ans[N],k,n,mi[N],ls[N],rs[N],fa[N],dl[N],d[N];

void dfs(int u){
    if(ls[u]){
        d[ls[u]]=d[u]+1;
        dfs(ls[u]);
    }
    if(rs[u]){
        d[rs[u]]=d[u]+1;
        dfs(rs[u]);
    }
}

int main(){
    mi[1]=1;mi[2]=2;
    for(int i=3;i<=3000;i++)
        mi[i]=mi[i-1]+mi[i-2]+1;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>fa[i];
        if(fa[i]!=-1){
            if(i<fa[i])ls[fa[i]]=i;
            else rs[fa[i]]=i;
        }
    }
    
    int root;
    for(int i=1;i<=n;i++)if(fa[i]==-1)root=i;
    dfs(root);
    
    for(int i=1;i<=n;i++)if(!ans[i]){
        int pre=fa[i],now=i,tot=k;
        while(pre!=-1){
            if(!ans[pre])tot--;//祖先没被选过 
            if(now==ls[pre]){//now是pre左子树 
                int t=d[i]-d[pre];
                if(dl[pre]<t)
                    tot-=mi[t-1]; 
                else tot-=mi[dl[pre]-1];
            }else{//now是pre右子树 
                if(!ans[pre]){tot=-1;break;}
                int t=d[i]-d[pre];
                if(t>dl[pre]+1){tot=-1;break;} 
            }
            now=pre;pre=fa[now];
        }
        if(tot>=1){
            ans[i]=1;k--;
            int pre=fa[i],now=i;
            while(pre!=-1){
                if(!ans[pre])ans[pre]=1,k--;
                if(now==ls[pre]){
                    int t=d[i]-d[pre];
                    if(dl[pre]<t){
                        dl[pre]=t;
                    }
                }
                now=pre;pre=fa[pre];
            }
        }else {
            ans[i]=0;
        }
    }
    
    for(int i=1;i<=n;i++)cout<<ans[i];
    
} 
View Code

标程好像用的是另一种方法。。

#include <cstdio>
#include <algorithm>
using namespace std;
 
int p,l,pi[233],pf[555555],pp[555555][2],dd[555555],pd[555555],pl[555555];
bool ff[555555];
 
void shu(int k,int d)
{
    if(k==0) return;
    dd[k]=d;
    shu(pp[k][0],d+1);
    shu(pp[k][1],d+1);
    pl[k]=max(pl[pp[k][0]],pl[pp[k][1]])+1;
    return;
}
 
void tui(int k,int d)
{
    if(k==0||d<=0) return;
    pd[k]=d; ff[k]=true;
    if(pl[pp[k][0]]>=d-1)
    {
        tui(pp[k][0],d-1);
        if(d-2>0) tui(pp[k][1],d-2);
    }
    else
    {
        tui(pp[k][1],d-1);
        if(d-2>0) tui(pp[k][0],d-2);
    }
    return;
}
 
bool shang(int k,int d,int &p)
{
    if(pf[k]==-1) return true;
    int t=p;
    if(k<pf[k])
    {
        if(ff[pf[k]]==false)
        {
            if(t==0) return false;
            t--;
        }
        if(pd[pp[pf[k]][1]]<d-2)
        {
            t-=pi[d-2]-pi[pd[pp[pf[k]][1]]];
            if(t<0) return false;
        }
        if(shang(pf[k],d+1,t))
        {
            ff[pf[k]]=true; p=t;
            pd[pf[k]]=max(pd[pf[k]],d);
            pd[pp[pf[k]][1]]=max(pd[pp[pf[k]][1]],d-2);
            return true;
        }
    }
    else
    {
        if(ff[pf[k]]==false||d-pd[pp[pf[k]][0]]>2) return false;
        if(shang(pf[k],d+1,t))
        {
            p=t;
            pd[pf[k]]=max(pd[pf[k]],d);
            return true;
        }
    }
    return false;
}
 
int main()
{
    pi[1]=1; pi[2]=2;
    for(int i=3; i<233; i++)
    {
        pi[i]=pi[i-1]+pi[i-2]+1;
        if(pi[i]>500000) break;
    }
    int n,root; scanf("%d%d",&n,&p);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&pf[i]);
        if(pf[i]==-1) root=i;
        else if(i<pf[i]) pp[pf[i]][0]=i;
        else pp[pf[i]][1]=i;
    }
    shu(root,1);
    for(int i=1; i<=n; i++)
    {
        if(ff[i]==true)
        {
            if(pd[pp[i][1]]>0) tui(pp[i][1],pd[pp[i][1]]);
            continue;
        }
        if(p==0) continue;
        int t=p-1;
        if(shang(i,2,t))
        {
            ff[i]=true; p=t;
            pd[i]=max(pd[i],1);
        }
    }
    for(int i=1; i<=n; i++) if(ff[i]==true)
        printf("1");
    else
        printf("0");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/12887984.html
cut