zoukankan      html  css  js  c++  java
  • Codechef August Challenge 2018 : Chef at the River

    传送门

    (要是没有tjm(Sakits)的帮忙,我还真不知道啥时候能做出来

    结论是第一次带走尽可能少的动物,使未带走的动物不冲突,带走的这个数量就是最优解。

    首先这个数量肯定是下界,更少的话连第一次都带不走。

    然后考虑带过去之后把某一只留在对岸,剩下的全部随身携带,这时有了一个空位,就可以慢慢把与留下的动物无关联的都挪到对岸去。再把随身携带的动物中与未到达对岸的任何一只都无关联的动物留着,其余的(包括之前单出来的)随身携带,这时有了一个空位可以再次慢慢挪。

    唯一的特殊情况是某一个点连接了剩余所有点,且总点数大于3,特判即可。

    接着是如何计算第一次最少带多少只的问题。

    取父亲必定不比取儿子差,我们可以维护这个贪心,这样就只有一种解。

    考虑某次多了一个点,肯定是从这个点往上某条链的状态取反,这条链延伸的终点必定是一个已取的点有其他未取的儿子。

    树剖之后维护每个点未取的轻儿子的个数,每次查询需要在线段树上二分一下。虽然看起来是两个log,但是明显跑不满,可以A(水)掉。

    #include<cstdio>
    #include<algorithm>
    #define MN 1100000
    #define lp p<<1
    #define rp p<<1|1
    using namespace std;
    
    int n,T,f[MN],_s[MN],l[MN],num,df[MN],lo[MN],s[MN],nm,son[MN],to[MN],ANS,t[MN<<2],Z[MN<<2],c[MN],w[MN],st[MN];
    bool b[MN<<2];
    inline int max(int x,int y){return x>y?x:y;}
    inline int min(int x,int y){return x<y?x:y;}
    struct na{int y,ne;}B[MN<<1];
    inline void add(int x,int y){B[++num].y=y;B[num].ne=l[x];l[x]=num;}
    void dfs(int x){
        s[x]=1;son[x]=0;
        for (int i=l[x];i;i=B[i].ne) if (dfs(B[i].y),s[x]+=s[B[i].y],s[B[i].y]>s[son[x]]) son[x]=B[i].y;
    }
    void DFS(int x,int q){
        df[x]=++nm;to[x]=q;
        if (son[x]) DFS(son[x],q);
        for (int i=l[x];i;i=B[i].ne)
        if (B[i].y!=son[x]) DFS(B[i].y,B[i].y);
        lo[x]=nm;
    }
    inline void rev(int p){
        b[p]^=1;
    }
    inline void pd(int p,int l,int r){
        if (b[p])
        if (b[p]=0,l!=r) rev(lp),rev(rp);
        else c[l]^=1;
    }
    void fz(int p,int l,int r,int L,int R){
        if (l==L&&r==R) {rev(p);return;}
        pd(p,l,r);
        int mid=l+r>>1;
        if (R<=mid) fz(lp,l,mid,L,R);else
        if (L>mid) fz(rp,mid+1,r,L,R);else
        fz(lp,l,mid,L,mid),fz(rp,mid+1,r,mid+1,R);
    }
    int ask(int p,int l,int r,int L,int R){
        //printf("%d %d %d %d %d %d %d %d
    ",p,l,r,L,R,t[p],t[lp],t[rp]);
        if (!t[p]) return 0;
        if (l==L&&r==R) return Z[p];
        pd(p,l,r);
        int mid=l+r>>1,tmp;
        if (R<=mid) return ask(lp,l,mid,L,R);else
        if (L>mid) return ask(rp,mid+1,r,L,R);else
        if (tmp=ask(rp,mid+1,r,mid+1,R)) return tmp;else return ask(lp,l,mid,L,mid);
    }
    bool col(int p,int l,int r,int k){
        pd(p,l,r);
        if (l==r) return c[k];
        int mid=l+r>>1;
        if (k<=mid) return col(lp,l,mid,k);else return col(rp,mid+1,r,k);
    }
    void ADD(int p,int l,int r,int k,int v){
        t[p]+=v;
        if (l==r){
            Z[p]=t[p]?l:0;
            return;
        }
        int mid=l+r>>1;
        if (k<=mid) ADD(lp,l,mid,k,v);else ADD(rp,mid+1,r,k,v);
        if (t[p]) if (t[rp]) Z[p]=Z[rp];else Z[p]=Z[lp];else Z[p]=0;
    }
    inline void work(int x){
        int tmp,top=0,la=0;
        while (x){
            if (son[x]&&col(1,1,n,df[x]+1)) break;
            if (tmp=ask(1,1,n,df[to[x]],df[x])){
                if (tmp!=df[x]) fz(1,1,n,tmp+1,df[x]),la=tmp+1;
                break;
            }
            //printf("===%d %d
    ",x,tmp);
            fz(1,1,n,df[to[x]],df[x]);
            la=df[to[x]];
            if (f[to[x]]){
                if (col(1,1,n,df[to[x]])){
                    st[++top]=f[to[x]];
                }else if (--w[f[to[x]]]==0) ADD(1,1,n,df[f[to[x]]],-1);
            }
            x=f[to[x]];
        }
        while (top){
            if (w[st[top]]++==0) ADD(1,1,n,df[st[top]],1);
            top--;
        }
        ANS+=!col(1,1,n,la);
        //printf("la:%d %d
    ",la,col(1,1,n,la));
        //for (int j=1;j<=n;j++) printf("col %d %d:%d
    ",j,df[j],col(1,1,n,df[j]));
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for (int i=1;i<=n;i++) _s[i]=l[i]=s[i]=son[i]=c[i]=w[i]=to[i]=0;num=nm=ANS=0;
            for (int i=1;i<=(n<<2);i++) t[i]=b[i]=Z[i]=0;
            for (int i=2;i<=n;i++){
                scanf("%d",&f[i]);
                add(f[i],i);
            }
            dfs(1);
            DFS(1,1);
            work(1);
            for (int i=2;i<=n;i++){
                _s[f[i]]++;
                work(i);
                printf("%d ",ANS+1+((_s[1]==i-1&&i>3||_s[1]==1&&_s[2]==i-2&&i>3)));
                //printf("%d
    ",ANS);
            }
            puts("");
        }
    }
    View Code
  • 相关阅读:
    获取和设置iframe中的元素
    css隔行换色样式修改
    在本地打开网页
    HTML-embed标签详解
    GlusterFS缺点分析[转]
    设计新Xlator扩展GlusterFS[转]
    C语言:全局变量在多个c文件中公用的方法 [转]
    const char*, char const*, char*const的区别
    C 语言字符数组的定义与初始化
    滑动窗口机制[转]
  • 原文地址:https://www.cnblogs.com/Enceladus/p/9494211.html
Copyright © 2011-2022 走看看