• [Wc]Dface双面棋盘()


    题解:

    一道维护奇怪信息的线段树。。。

    我刚开始看了标签想的是删去图上一个点后求连通性

    发现不会

    于是退化成一般图支持删除 插入 维护连通性

    发现有2两种做法

    1.lct维护

    按照结束顺序先后排序,给每条边一个权值

    然后我们只要维护最大生成树就好了,因为这样可以保证删除当前树上的边是不会被权值更小的边替换的

    而由于最大生成树的性质,是不可能能替换成更大的边的

    so这说明删除它之后就不需要连边了

    nlogn^2但是常数大吧

    2.线段树分治

    这个应该很明显吧,变成只有插入的并查集问题

    nlogn^2logn^2 本来常数不大但是自带了4

     写代码:1h

    debug:30min

    #pragma G++ optimize (2)
    #include <bits/stdc++.h>
    using namespace std;
    #define IL inline
    #define rint register int
    char ss[1<<24],*A=ss,*B=ss;
    IL char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;}
    template<class T>void read(T&x){
        rint f=1,c;while(c=gc(),c<48||57<c)if(c=='-')f=-1;x=c^48;
        while(c=gc(),47<c&&c<58)x=(x<<3)+(x<<1)+(c^48);x*=f;
    }
    char sr[1<<24],z[20];int C=-1,Z;
    template<class T>void wer(T x){
        if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]=' ';
    }
    const int N=210;
    const int N2=1e4+1e3;
    int a[N][N],f1[N][N][5],f0[N][N][5],n,m;
    int dx[5]={0,1,-1,0,0};
    int dy[5]={0,0,0,1,-1};
    int pos[5]={0,2,1,4,3};
    IL bool pd(int x,int y)
    {
      if (1<=x&&x<=n&&1<=y&&y<=n) return(1);
      else return(0);
    }
    struct re{
      int a,b,c;
    };
    IL int js(int x,int y)
    {
      return(x*n+y);
    }
    struct sgt
    {
      vector<re> ve[N2*4];
      int fa[N*N],count2[N*N],ans[N2];
      sgt() { for (int i=1;i<=N*N-1;i++) fa[i]=i,count2[i]=1;}
      #define mid ((h+t)>>1)
      void insert(int x,int h,int t,int h1,int t1,re k)
      {
        if (h1>t1) return; 
        if (h1<=h&&t<=t1)
        {
          ve[x].push_back(k); return; 
        }
        if (h1<=mid) insert(x*2,h,mid,h1,t1,k);
        if (mid<t1) insert(x*2+1,mid+1,t,h1,t1,k);
      }
      IL int find(int &x)
      {
        while (fa[x]!=x) x=fa[x];  
      }
      void dfs(int x,int h,int t,int cnt)
      {
       // cout<<x<<" "<<h<<" "<<t<<endl;
        stack<re> s;
        int cnt2=cnt;
        for (rint i=0;i<ve[x].size();i++)
        {
          re t=ve[x][i];
          rint x1=js(t.a,t.b),x2=js(t.a+dx[t.c],t.b+dy[t.c]);
          find(x1); find(x2);
          if (x1!=x2)
          {
            if (count2[x1]>count2[x2]) swap(x1,x2);
            cnt2++;
            s.push((re){x1,x2,count2[x2]});
            fa[x1]=x2; count2[x2]+=count2[x1];
          }
        }
        if (h==t) ans[h]=cnt2;
        else
        {
          dfs(x*2,h,mid,cnt2); 
          dfs(x*2+1,mid+1,t,cnt2);
        }
        while (!s.empty())
        {
          re t=s.top(); s.pop();
          fa[t.a]=t.a; count2[t.b]=t.c;
        }
      }
    }se1,se0; 
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      read(n);
      int ans[2][N2]={};
      for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
          read(a[i][j]);
          ans[a[i][j]][0]++;
        }
      for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
          for(int k=1;k<=4;k++)
            f1[i][j][k]=-1,f0[i][j][k]=-1;
      for(int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
          for(int k=1;k<=4;k++)
            if (pd(i+dx[k],j+dy[k])&&a[i][j]==a[i+dx[k]][j+dy[k]])
              if (a[i][j]) f1[i][j][k]=0;
              else f0[i][j][k]=0; 
      read(m);
      for (int i=1;i<=m;i++)
      {
        int x,y;
        read(x); read(y);
        for (int k=1;k<=4;k++)
          if (pd(x+dx[k],y+dy[k]))
            if (a[x][y]==1)
            {
              if (a[x+dx[k]][y+dy[k]]==a[x][y])
                se1.insert(1,1,m,max(f1[x][y][k],1),i-1,(re){x,y,k}),
                f1[x][y][k]=-1,f1[x+dx[k]][y+dy[k]][pos[k]]=-1;
              else
                f0[x][y][k]=i,f0[x+dx[k]][y+dy[k]][pos[k]]=i;
            }
            else
              if (a[x+dx[k]][y+dy[k]]==a[x][y])
                se0.insert(1,1,m,max(f0[x][y][k],1),i-1,(re){x,y,k}),
                f0[x][y][k]=-1,f0[x+dx[k]][y+dy[k]][pos[k]]=-1;
              else
                f1[x][y][k]=i,f1[x+dx[k]][y+dy[k]][pos[k]]=i;
        if(a[x][y]==0) ans[1][i]=ans[1][i-1]+1,ans[0][i]=ans[0][i-1]-1;
        else ans[0][i]=ans[0][i-1]+1,ans[1][i]=ans[1][i-1]-1;
        a[x][y]^=1;
      }
      for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
          for (int k=1;k<=4;k++)
          {
            if (f1[i][j][k]>=0)
            { 
              se1.insert(1,1,m,max(1,f1[i][j][k]),m,(re){i,j,k});
            }
            if (f0[i][j][k]>=0)
            { 
              se0.insert(1,1,m,max(1,f0[i][j][k]),m,(re){i,j,k});
            }
          }
    /*  for (int i=1;i<=1;i++)
        for (int j=0;j<se1.ve[i].size();j++)
          cout<<se1.ve[1][j].a<<" "<<se1.ve[1][j].b<<" "<<se1.ve[1][j].c<<endl;
      cout<<endl; */
      se1.dfs(1,1,m,0);
      se0.dfs(1,1,m,0);
      for(int i=1;i<=m;i++) 
        wer(ans[1][i]-se1.ans[i]),wer(ans[0][i]-se0.ans[i]),sr[++C]='
    ';
      fwrite(sr,1,C+1,stdout);
      // changshi fen ge fu
      return 0;
    }

    然后由于这个牵扯出loj122这题 维护动态图连通性

    并没有看懂网上的唯一一篇题解于是弃疗

    正解:

    线段树上的每个叶子节点表示一行

    每个节点维护当前范围内的黑白区间个数

    合并的时候就用并查集启发式合并就可以

    每次合并是o(n)的

    每次修改进行log次

    所以复杂度应该是O(nmlogn)

    相比上面两种都不优吧 但是常数小了至少2倍  因为这个是单点修改上面的要修改4条边

    写完我发现我这种写法极其冗长

    由于0,1完全等价

    完全可以把它们弄成结构题然后修改做两次 这样代码就可以短大约一半低于普遍长度了

    写代码:1h+

    调试:40min

    数据结构的代码能力很需要提升啊

    如果这题能做到30min写完20min调完我觉得那就能很强了

    不过这个时间我觉得写得常数可能非常大

    经过优化的线段树分治只用了0.3s不到(本地)

    这个用了2.4s

    主要消耗时间的无疑是updata这里

    我写得时候想的是先将两个儿子合并在一起,然后再搞

    然后我就合并了4*n

    其实只要中间的2*n就可以了,这样常数是2

    另外我刚开始统计联通块数目用的是一个很傻比的方法

    里面的一些信息没删可能也导致了时间的增加

    于是我决定再去卡一波常数

    这个是源代码:

    #pragma G++ optimize (2)
    #include <bits/stdc++.h>
    using namespace std;
    #define IL inline
    #define rint register int
    char ss[1<<24],*A=ss,*B=ss;
    IL char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;}
    template<class T>void read(T&x){
        rint f=1,c;while(c=gc(),c<48||57<c)if(c=='-')f=-1;x=c^48;
        while(c=gc(),47<c&&c<58)x=(x<<3)+(x<<1)+(c^48);x*=f;
    }
    char sr[1<<24],z[20];int C=-1,Z;
    template<class T>void wer(T x){
        if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]=' ';
    }
    const int N=210;
    const int N2=1e4+1e3;
    int a[N][N],n,m,ph[N*4],pt[N*4];
    struct bcj{
      int fa[N*4][N*2],data[N*4];
      int find(int x,int y)
      {
        int ans;
        if (fa[x][y]!=y) ans=find(x,fa[x][y]);
        else return(y);
        fa[x][y]=ans;
        return(ans);
      }
    }b1,b2;
    struct mn{
      int fa[N*4],pos[N*4];
      bool f[N*4];
      int find(int x)
      {
        int ans;
        if (fa[x]!=x) ans=find(fa[x]);
        else return(x);
        fa[x]=ans;
        return(ans);
      }
    }c1,c2;
    IL bool pd(int x)
    {
      if ((1<=x&&x<=n)||(3*n<x&&x<=4*n)) return(1);
      else return(0);
    }
    IL int mex(int x,int y)
    {
      if (y==0) return(0);
      else return(x+y);
    }
    void updata(int x)
    {
      int h1=ph[x*2],t1=pt[x*2],h2=ph[x*2+1],t2=pt[x*2+1];
      for (int i=1;i<=2*n;i++) 
        c1.fa[i]=b1.fa[x*2][i],c2.fa[i]=b2.fa[x*2][i];
      for (int i=1;i<=2*n;i++) 
        c1.fa[i+2*n]=mex(2*n,b1.fa[x*2+1][i]),
        c2.fa[i+2*n]=mex(2*n,b2.fa[x*2+1][i]);
      int cnt1=0,cnt2=0;
      for (int i=1;i<=n;i++)
        if (a[t1][i]==a[h2][i])
          if (a[t1][i])
          {
            int x1=c1.find(n+i);
            int x2=c1.find(2*n+i);
            if (x1!=x2&&x1!=0&&x2!=0) c1.fa[x1]=x2,cnt1++;
          } else
          {
            int x1=c2.find(n+i);
            int x2=c2.find(2*n+i);
            if (x1!=x2&&x1!=0&&x2!=0) c2.fa[x1]=x2,cnt2++;
          }
      for (int i=1;i<=4*n;i++) 
        c1.f[i]=c2.f[i]=c1.pos[i]=c2.pos[i]=0;
      c1.f[0]=c2.f[0]=1; 
      for (int i=1;i<=n;i++)
      {
        int x1=c1.find(i);
        if (x1)
        if (pd(x1))
        {
          b1.fa[x][i]=x1;
          if(!c1.f[x1]) c1.f[x1]=1;
        }
        else
          if (c1.pos[x1]) b1.fa[x][i]=c1.pos[x1];
          else b1.fa[x][i]=i,c1.pos[x1]=i;
        
        int x2=c2.find(i);
        if (x2)
        if (pd(x2))
        { 
          b2.fa[x][i]=x2;
          if(!c2.f[x2]) c2.f[x2]=1;
        }
        else
          if (c2.pos[x2]) b2.fa[x][i]=c2.pos[x2];
          else b2.fa[x][i]=i,c2.pos[x2]=i;
      }
      for(int i=3*n+1;i<=4*n;i++)
      {
        int x1=c1.find(i);
        if (x1)
        if (pd(x1))
        { 
          b1.fa[x][i-2*n]=x1;
          if(!c1.f[x1]) c1.f[x1]=1;
        } 
        else
          if (c1.pos[x1]) b1.fa[x][i-2*n]=c1.pos[x1];
          else b1.fa[x][i-2*n]=i,c1.pos[x1]=i;
        
        int x2=c2.find(i);
        if (x2)
        if (pd(x2))
        { 
          b2.fa[x][i-2*n]=x2;
          if(!c2.f[x2]) c2.f[x2]=1;
        }
        else
          if (c2.pos[x2]) b2.fa[x][i-2*n]=c2.pos[x2];
          else b2.fa[x][i-2*n]=i,c2.pos[x2]=i;
      }
      b1.data[x]=b1.data[x*2]+b1.data[x*2+1]-cnt1; 
      b2.data[x]=b2.data[x*2]+b2.data[x*2+1]-cnt2;
      for (int i=1;i<=2*n;i++)
      {
        if (b1.fa[x][i]>2*n) b1.fa[x][i]-=2*n;
        if (b2.fa[x][i]>2*n) b2.fa[x][i]-=2*n;
      }
    }
    #define mid ((h+t)/2)
    void build(int x,int h,int t)
    {
      ph[x]=h; pt[x]=t;
      if (h==t)
      {
        int cnt1=0,cnt2=0;
        for (int i=1;i<=n;i++)
        if (a[h][i])
          b1.fa[x][i]=i,b2.fa[x][i]=0,cnt1++;
        else
          b1.fa[x][i]=0,b2.fa[x][i]=i,cnt2++;
        for (int i=n+1;i<=2*n;i++)
          b1.fa[x][i]=b1.fa[x][i-n],b2.fa[x][i]=b2.fa[x][i-n];
        for (int i=1;i<=n-1;i++)
          if (a[h][i]==a[h][i+1])
            if (a[h][i])
            {
              int x1=b1.find(x,i);
              int x2=b1.find(x,i+1);
              if (x1!=x2)
                b1.fa[x][x1]=x2,cnt1--;
            } else
            {
              int x1=b2.find(x,i);
              int x2=b2.find(x,i+1);
              if (x1!=x2)
                b2.fa[x][x1]=x2,cnt2--;
            }
        b1.data[x]=cnt1;
        b2.data[x]=cnt2;
        return;
      }
      build(x*2,h,mid); build(x*2+1,mid+1,t); 
      updata(x);
    }
    
    void change(int x,int h,int t,int pos,int k)
    {
      if (h==t)
      {
        a[pos][k]^=1;
        int cnt1=0,cnt2=0;
        for (int i=1;i<=n;i++)
        if (a[h][i])
          b1.fa[x][i]=i,b2.fa[x][i]=0,cnt1++;
        else
          b1.fa[x][i]=0,b2.fa[x][i]=i,cnt2++;
        for (int i=n+1;i<=2*n;i++)
          b1.fa[x][i]=b1.fa[x][i-n],b2.fa[x][i]=b2.fa[x][i-n];
        for (int i=1;i<=n-1;i++)
          if (a[h][i]==a[h][i+1])
            if (a[h][i])
            {
              int x1=b1.find(x,i);
              int x2=b1.find(x,i+1);
              if (x1!=x2)
                b1.fa[x][x1]=x2,cnt1--;
            } else
            {
              int x1=b2.find(x,i);
              int x2=b2.find(x,i+1);
              if (x1!=x2)
                b2.fa[x][x1]=x2,cnt2--;
            }
        b1.data[x]=cnt1;
        b2.data[x]=cnt2;
        return;
      }
      if (pos<=mid) change(x*2,h,mid,pos,k);
      else change(x*2+1,mid+1,t,pos,k);
      updata(x);
    }
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      read(n);
      for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
          read(a[i][j]);
      build(1,1,n);
     // cout<<b1.data[1]<<" "<<b2.data[1]<<endl;
      read(m);
      for (int i=1;i<=m;i++)
      {
        int x,y;
        read(x); read(y);
        change(1,1,n,x,y);
        wer(b1.data[1]);
        wer(b2.data[1]);
        sr[++C]='
    ';
      }
      fwrite(sr,1,C+1,stdout);
      return 0;
    }
  • 相关阅读:
    Java基础学习(二)——对象
    Java基础学习(一)
    设置eclipse代码自动补全功能
    C# 之泛型详解(转)
    查找项目的代码行数(适用于VS)
    转: rdlc报表An error occurred during local report processing错误
    自己创建的Window服务,经常变为挂起状态,重启失败的处理
    C# 项目引用WebService,提示报错“在 ServiceModel 客户端配置部分中,找不到引用协定...”
    轉 @@identity与scope_identity()函数的区别
    JS window.onload事件的一些理解
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/9070055.html
Copyright © 2020-2023  润新知