zoukankan      html  css  js  c++  java
  • [Luogu P6044]「ACOI2020」惊吓路径

    题目链接:Luogu P6044

    强行卡内存差评

    首先对于一个固定的(v)(u)显然是有单调性的:若一个点(u)满足条件,则(u)的所有祖先都满足条件

    那么就有了一个简单的做法,枚举所有的(v),找到最深的(u),对答案的贡献就是(u)的深度

    我们可以用倍增来加速这个过程,即不断向上跳找到最浅的点(x)不满足条件,那么(x)的父亲就是最深的(u)

    倍增数组就有两个,一个(f[i][x])表示(x)(2^i)级祖先,一个(g[i][x])表示从(x)向上(2^i)个点的或和。

    然后问题来了,出题人卡内存怎么办?(倍增数组就要(152M)

    我的方法是在DFS的过程中用一个栈维护根到(v)的这条链,实时维护(g)数组

    这样的话我们就不需要(f)数组了!(直接在栈里往前移(2^i)个位置就好了)

    这样就可以不特判过Subtask2了!

    不知道为什么我的DFS会用掉(60M)的栈空间。。没办法只能手动模拟DFS了,极限数据约(100M)内存。

    时间复杂度 (O(nlog n))

    空间复杂度 (O(nlog n))

    代码:

    //不带IO优化的版本
    #include <cstdio>
    #define rint register int
    typedef long long ll;
    
    const int N=1000005;
    int n,k,c[N],s[N],Top;
    int Head[N],Next[N],To[N],En;
    int f[20][N];
    bool Son[N];
    ll Ans;
    
    inline void Add(int x,int y){Next[++En]=Head[x],To[Head[x]=En]=y;}
    
    void Calc(int x)//将点x入栈并计算x的贡献
    {
        s[++Top]=x,f[0][Top]=c[x];
        for(int i=1;1<<i<=Top;++i)f[i][Top]=f[i-1][Top]|f[i-1][Top-(1<<(i-1))];
        int p=Top+1,v=0;
        for(int i=19;i>=0;--i)
            if((1<<i)<p&&(f[i][p-1]|v)<k)
                v|=f[i][p-1],p-=1<<i;
        Ans+=p-1;
    }
    
    void BFS(int x)//并不是BFS
    {
        Calc(x);
        while(Top)
            if(Head[x=s[Top]])Calc(To[Head[x]]),Head[x]=Next[Head[x]];//向下DFS
            else --Top;//回溯
    }
    
    int main()
    {
        scanf("%d%d",&n,&k);
        for(rint i=1;i<=n;++i)scanf("%d",&c[i]);
        for(rint i=2,x,y;i<=n;++i)scanf("%d%d",&x,&y),Add(x,y),Son[y]=true;
        for(rint i=1;i<=n;++i)if(!Son[i])BFS(i),i=n;
        return printf("%lld
    ",Ans),0;
    }
    
  • 相关阅读:
    并发工具类的使用 CountDownLatch,CyclicBarrier,Semaphore,Exchanger
    多线程按顺序执行3个方法
    读写锁事例
    使用AQS自定义重入锁
    java 几种锁实现
    Nginx 安装
    Windows 安装mysql
    day--14前端(HTML、CSS)
    day13--开发堡垒机
    day12--python操作mysql
  • 原文地址:https://www.cnblogs.com/LanrTabe/p/12252926.html
Copyright © 2011-2022 走看看