• CF1534F2Falling Sand (Hard Version)


    正题

    题目链接:https://www.luogu.com.cn/problem/CF1534F2


    题目大意

    有一个\(n*m\)个网格,有的网格上有沙子,一个沙子被刷新后会下落到底并且刷新沿途中四周四连通的沙子,你可以选择一些沙子手动刷新。

    现在要求第\(i\)列至少有\(a_i\)个沙子下落,求至少手动刷新多少个沙子。

    \(1\leq n\times m\leq 4\times 10^5\)


    解题思路

    显然列要求的\(a_i\)就是要求最下面的那\(a_i\)个沙子被刷新。

    手动刷新的肯定都是每一列位置最高的沙子,然后刷新关系可以表示成一张有向图,而且是平面图,那么就说明一个沙子被刷新的条件是手动刷新了某个区间中位置最高的沙子。

    我们考虑求出这些区间,先建边,这样最多\(4nm\)条边,然后对于每个沙子要求区间的左端点我们从左往右从最高的沙子开始跑,然后每次走到的点标记删除,右区间就变成从右往左跑。

    得到这些区间后我们转换成若干个形如区间\([l,r]\)中必须要有一个\(1\)的限制,然后考虑\(dp\),用单调队列优化一下即可。

    时间复杂度:\(O(nm)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define p(x,y) ((((x)-1)*n)+(y))
    using namespace std;
    const int N=8e5+10;
    struct node{
        int to,next;
    }a[N*4];
    int n,m,tot,ls[N],l[N],r[N],lim[N],f[N];
    deque<int> q;vector<int> v[N];char s[N];
    void addl(int x,int y){
        a[++tot].to=y;
        a[tot].next=ls[x];
        ls[x]=tot;return;
    }
    void dfsl(int x){
        for(int i=ls[x];i;i=a[i].next){
            int y=a[i].to;
            if(l[y])continue;
            l[y]=l[x];dfsl(y);
        }
        return;
    }
    void dfsr(int x){
        for(int i=ls[x];i;i=a[i].next){
            int y=a[i].to;
            if(r[y])continue;
            r[y]=r[x];dfsr(y);
        }
        return;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%s",s+1);
            for(int j=1;j<=m;j++)
                if(s[j]=='#')
                    v[j].push_back(n-i+1);
        }
        for(int i=1;i<=m;i++){
            if(v[i].empty())continue;
            for(int j=0;j<v[i].size()-1;j++){
                addl(p(i,v[i][j]),p(i,v[i][j+1]));
            	if(v[i][j+1]+1==v[i][j])addl(p(i,v[i][j+1]),p(i,v[i][j]));
            }
            for(int g=-1;g<2;g++){
                if(!g||!v[i+g].size())continue;
                int z=0,_=0;
                while(z<v[i+g].size()&&v[i+g][z]>v[i][0])z++;
                for(int h=v[i][0];h>=1;h--){
                    if(_<v[i].size()-1&&h==v[i][_+1])_++;
                    if(z<v[i+g].size()&&h==v[i+g][z])
                        addl(p(i,v[i][_]),p(i+g,v[i+g][z])),z++;
                }
            }
        }
        for(int i=1;i<=m;i++){
            if(v[i].empty())continue;
            int x=p(i,v[i][0]);
            if(!l[x])l[x]=i,dfsl(x);
        }
        for(int i=m;i>=1;i--){
            if(v[i].empty())continue;
            int x=p(i,v[i][0]);
            if(!r[x])r[x]=i,dfsr(x);
        }
        for(int i=1,x;i<=m;i++){
            scanf("%d",&x);
            for(int j=v[i].size()-1;j>=(int)v[i].size()-x;j--)
            {int y=p(i,v[i][j]);lim[r[y]]=max(lim[r[y]],l[y]);}
        }
        q.push_back(0);
        for(int i=1;i<=m;i++){
            f[i]=max(f[i],f[q.front()]+1);
            while(!q.empty()&&f[q.back()]>=f[i])q.pop_back();
            q.push_back(i);
            while(!q.empty()&&q.front()<lim[i])q.pop_front();
        }
        printf("%d\n",f[q.front()]);
        return 0;
    }
    
  • 相关阅读:
    linux利用yum下载rpm离线包
    Struts Spring Plugin注意点
    Spring 对没有实现接口的类使用aspect的时候,可以使用CGLIB
    Spring HibernateTemplate
    Spring 声明式事务管理
    Spring 配置dataSource和sessionFactory
    Spring 配置中的 ${}
    Srping AOP xml方式
    Spring AOP 面向切面编程相关注解
    Spring 常用注入注解(annotation)和其对应xml标签
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/16573737.html
Copyright © 2020-2023  润新知