zoukankan      html  css  js  c++  java
  • 平衡树性质+思维——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;
    }
  • 相关阅读:
    HDU 4472 Count DP题
    HDU 1878 欧拉回路 图论
    CSUST 1503 ZZ买衣服
    HDU 2085 核反应堆
    HDU 1029 Ignatius and the Princess IV
    UVa 11462 Age Sort
    UVa 11384
    UVa 11210
    LA 3401
    解决学一会儿累了的问题
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12887984.html
Copyright © 2011-2022 走看看