• ZJNU 2663


    ZJNU 2663 - SLIKA

    题面

    description

    有一个(n imes n)的网格图,(k)种颜色,(m)次操作,棋盘初始时颜色均为(1)

    操作分三种,第一种操作(PAINT)会选择一个矩形区域与一种颜色,要求按棋盘方式对选定的区域涂色,如上图所示;后涂的颜色会覆盖在先前涂的颜色上。

    第二种操作(SAVE)会保存一个副本,递增编号。

    第三种操作(LOAD)则会加载先前保存的副本。

    问按顺序执行完所有操作后,网格最终的状态。


    思路

    忘了哪里有做到过一次,也是逆序还原操作来优化

    至于利用并查集来跳过已使用的部分的话,印象里2020ICPC银川站的某道银冲金题(加点手速和少罚时)也是这个做法,算是比较常见的

    按顺序进行,时间复杂度(O(mcdot n^2)),空间复杂度(O(mcdot n^2)),均不可行。

    首先考虑(SAVE)(LOAD)操作,执行(LOAD)操作后,会跳转至先前的某一存档,也就说明从那个存档开始到当前的(LOAD)操作之间的所有(PAINT)在此时均被忽略掉了。

    发现按顺序进行(PAINT)操作时,后面进行的操作的涂色会将先前的涂色给覆盖掉;也就是说如果逆序看所有的操作,产生位置冲突时后面的操作将会跳过该位置的涂色。

    因此,如果我们能够快速将该跳过的位置直接跳过,最终涂色操作最多也就只会做(n^2)级别次,而不是按顺序执行所有操作时最坏情况下需要进行(mcdot n^2)级别次。

    那么考虑快速跳过已经被涂色的位置,发现可以将每一行都单独看作一个并查集,如果我们只枚举待涂色区域的某一维(行),然后借助并查集跳过已经被涂色的位置(列),那么最终的时间复杂度实际上只有操作数与枚举数的乘积,即(O(mcdot n))

    考虑实现,假设当前我们将位置((i,j))进行涂色,保证行独立处理((i)不变),因此向右的下一个涂色的位置应是((i,j+2))。定义(to[i][j])表示在位置((i,j))时,下一个待处理的(y)轴坐标,利用并查集维护。那么每次涂色之后执行的应当就是将(to[i][j])合并到(to[i][j+2])(注意向右合并)。合并后则直接让(y=find(x,to[x][y]))跳至下一个(y)坐标即可((find(x,y))函数即对于(x)行的查询),借助路径压缩优化过程。

    最后考虑(SAVE)(LOAD),在倒序看所有操作时,每一次(LOAD)实际上就是跳过了与其对应的(SAVE)操作到它之间的所有(PAINT)操作(在那一次(SAVE)之后的所有(PAINT)都因为这一次(LOAD)无效了),所以该部分简单处理以下,其后直接跳转操作数即可。


    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i<(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    #define perr(i,a,b) for(int i=(a);i>(b);i--)
    #define all(a) (a).begin(),(a).end()
    #define mst(a,b) memset(a,b,sizeof(a))
    #define pb push_back
    using namespace std;
    typedef long long ll;
    
    int n,k,q;
    struct node
    {
        int op,clr,x1,y1,x2,y2;
    }ar[100050];
    int savepos[100050],loadto[100050],savecnt=0;
    // PAINT SAVE LOAD
    
    int to[1050][1050];
    int fnd(int x,int a){
        return a==to[x][a]?a:(to[x][a]=fnd(x,to[x][a]));
    }
    void merge(int x,int a,int b){
        to[x][a]=fnd(x,to[x][b]);
    }
    int ans[1050][1050];
    
    void solve()
    {
        cin>>n>>k>>q;
        repp(i,0,n)
            repp(j,0,n)
                ans[i][j]=1;
                
        rep(i,1,q)
        {
            string s;
            cin>>s;
            if(s[0]=='P')
            {
                ar[i].op=1;
                cin>>ar[i].clr;
                cin>>ar[i].x1;
                cin>>ar[i].y1;
                cin>>ar[i].x2;
                cin>>ar[i].y2;
            }
            else if(s[0]=='S')
            {
                ar[i].op=2;
            }
            else
            {
                ar[i].op=3;
                cin>>ar[i].clr;
            }
        }
        rep(i,1,q)
        {
            if(ar[i].op==2)
                savepos[++savecnt]=i;
        }
        rep(i,1,q)
        {
            if(ar[i].op==3)
                loadto[i]=savepos[ar[i].clr];
        }
        repp(x,0,n)
            rep(y,0,n+1) //y会与y+2合并,注意边界情况
            {
                to[x][y]=y;
            }
        per(i,q,1)
        {
            if(ar[i].op==1)
            {
                rep(x,ar[i].x1,ar[i].x2)
                {
                    int y=ar[i].y1+(x-ar[i].x1)%2; //起始y
                    for(y=fnd(x,to[x][y]);y<=ar[i].y2;y=fnd(x,to[x][y]))
                    {
                        ans[x][y]=ar[i].clr;
                        merge(x,y,y+2); //涂色后将y与y+2合并
                    }
                }
            }
            else if(ar[i].op==2)
                continue;
            else
                i=loadto[i];
        }
        repp(i,0,n)
            repp(j,0,n)
                cout<<ans[i][j]<<(j==n-1?'
    ':' ');
    }
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        solve();
        return 0;
    }
    

  • 相关阅读:
    创建一个 mac 的后台进程(daemon)
    Centos 7创建一个服务
    MAC配置VIM环境
    Spark源码剖析(九):TaskScheduler原理与源码剖析
    Spark源码剖析(八):stage划分原理与源码剖析
    教你如何写递归(数学归纳法,干货强推!)
    Spark源码剖析(七):Job触发流程原理与源码剖析
    剑指offer:变态跳台阶
    Spark源码剖析(六):Worker原理与源码剖析
    Spark源码剖析(五):Master原理与源码剖析(下)
  • 原文地址:https://www.cnblogs.com/stelayuri/p/15185547.html
Copyright © 2020-2023  润新知