zoukankan      html  css  js  c++  java
  • P4117 【[Ynoi2018]五彩斑斓的世界】题解

    P4117 【[Ynoi2018]五彩斑斓的世界】

    "突刺贯穿的第二分块"

    调了一天的第二分块最后发现是 memset 的问题。。。(机房巨佬nb)

    大致思路相信第一篇题解已经讲的很清楚了,这里珂以再作阐述:

    考虑分块:对于每一个大小为 (sqrt{n}) 的块,

    先考虑修改:

    设整个块的最大值为 maxn ,修改值为 x 珂以分两种情况处理:

    1. (x*2<=maxn-tag), 对于这个块里的值,如题意一般,将所有(geq x)的数都(-x),修改后的 (maxn) 依旧不变

    2. (x*2>maxn-tag) 对于整个块的操作其实也就等价于将所有(leq x)(+x),再将整个区间打上一个(-x)(tag)

    再用一个并查集维护值域,

    记录下这个值下的(size),与这个值第一次出现位置(st),还有第一次出现位置所对应的映射 (rev)

    操作1也就相当于将(ain(tag+x,maxn])中的每个数都与(a-x)合并

    操作2也就相当于先将(a in [tag+1,x+tag])(a+x) 合并,再打上一个 (-x)(tag)

    对于不属于整块的操作直接暴力重新构造就好了

    查询的时候整块直接查 (x+tag)(size)

    不属于的直接暴力求解就好了

    然后出题人的题解中,有一个逐块处理的trick

    大致就是统计每一个块对于每一个询问的贡献,这样就可以做到(O(N+M))

    这个优化的很多前提珂以看这篇题解

    还有记住每一次统计的时候记得清空并查集中的信息,但是重构的时候不用清空,(我的惨烈调试记录)

    丑陋的代码~~~

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
       int x=0,f=1; char ch=getchar();
      while(!isdigit(ch)){if(ch=='-'){f=-1;}ch=getchar();}
      while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch-'0');ch=getchar();}
      return x*f;
    }
    inline void write( int x){
      if(x==0){putchar(48);putchar('
    ');return;}int len=0,dg[20];
      while(x>0){dg[++len]=x%10;x/=10;}
      for( int i=len;i>=1;i--) putchar(dg[i]+48);
      putchar('
    ');
    }
    const int MAXN=1e6+5,N=1e6+5,SQRTN=1e4+5,M=1e6+5;;
    int n,m,L[MAXN],R[MAXN],a[N],ans[M];
    int st[MAXN],fa[MAXN],size[MAXN],rev[MAXN],maxn,tag_dec;
    int ql[M],qr[M],qx[M],op[M],len;
    inline int get(int x){return fa[x]==x ? x : fa[x]=get(fa[x]);}
    inline void merge(int x,int y){
      if(st[y]){fa[st[x]]=st[y];}
      else{st[y]=st[x];rev[st[y]]=y;}
      size[y]+=size[x];st[x]=size[x]=0;
    }
    inline void pre_build(){
      len=sqrt(n);
      for( int i=1;i<=len;++i){L[i]=(i-1)*len+1;R[i]=i*len;}
      if(R[len]<n){len++;L[len]=R[len-1]+1;R[len]=n;}
    }
    inline void build_each(int num){
      maxn=0,tag_dec=0;
      for( int i=L[num];i<=R[num];++i){
        maxn=max(maxn,a[i]);
        if(st[a[i]]){fa[i]=st[a[i]];}
        else{st[a[i]]=fa[i]=i;rev[i]=a[i];}
        size[a[i]]++;
      }
    }
    inline void modify(int x){
      if(maxn-tag_dec>=x*2){
        for( int i=tag_dec+1;i<=tag_dec+x;++i){if(st[i]){merge(i,x+i);}}
        tag_dec+=x;
      }
      else{
        for( int i=x+tag_dec+1;i<=maxn;++i){if(st[i]){merge(i,i-x);}}
        maxn=min(maxn,tag_dec+x);
      }
    }
    inline void rebuild(int num,int queryl,int queryr,int x){
      for( int i=L[num];i<=R[num];++i){
        a[i]=rev[get(i)];
        st[a[i]]=size[a[i]]=0;
        a[i]-=tag_dec;
      }
      for( int i=L[num];i<=R[num];++i){rev[i]=0;}
      int lim=min(queryr,R[num]);
      int liml=max(L[num],queryl);
      for( int i=liml;i<=lim;++i){a[i]=a[i]-(a[i]>x)*x;}
      build_each(num);
    }
    inline void query(int num,int querynum){
      int x=qx[querynum],queryr=qr[querynum],queryl=ql[querynum];
      if(x+tag_dec>5e5){return;}
      if(queryl<=L[num]&&R[num]<=queryr){ans[querynum]+=size[x+tag_dec];}
      else{
        int lim=min(queryr,R[num]);
        int liml=max(queryl,L[num]);
        for(int i=liml;i<=lim;++i){if(rev[get(i)]==x+tag_dec){ans[querynum]++;}}
      }
    }
    inline void check(){puts("??????woc?????");}
    int main(){
      n=read(),m=read();
      for( int i=1;i<=n;++i){a[i]=read();}
      pre_build();
      for( int i=1;i<=m;++i){op[i]=read(),ql[i]=read(),qr[i]=read(),qx[i]=read();}
      for( int i=1;i<=len;++i){
        memset(st,0,sizeof(st));
        memset(size,0,sizeof(size));
        build_each(i);
        for( int j=1;j<=m;++j){
          if(qr[j]<L[i]||ql[j]>R[i]){continue;}
          if(op[j]==1){
            if(L[i]>=ql[j]&&R[i]<=qr[j]){modify(qx[j]);}
            else{rebuild(i,ql[j],qr[j],qx[j]);}
          }
          else{query(i,j);}
        }
      }
      for(int i=1;i<=m;++i){if(op[i]==2){write(ans[i]);}}
      return 0;
    }
    
    
    
  • 相关阅读:
    vim复制
    嵌入式Linux学习(二)
    (Java实现) 洛谷 P1042 乒乓球
    (Java实现) 洛谷 P1042 乒乓球
    (Java实现) 洛谷 P1071 潜伏者
    (Java实现) 洛谷 P1071 潜伏者
    (Java实现) 洛谷 P1025 数的划分
    (Java实现)洛谷 P1093 奖学金
    (Java实现)洛谷 P1093 奖学金
    Java实现 洛谷 P1064 金明的预算方案
  • 原文地址:https://www.cnblogs.com/NuoCarter/p/14448876.html
Copyright © 2011-2022 走看看