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;
    }
    
    
    
  • 相关阅读:
    爆打团队 2016.04.12 站立会议
    爆打团队 2016.04.11 站立会议
    爆打团队 2016.04.10 站立会议
    爆打小组 4.3日站立会议
    随机生成题目的代码分析
    爆打 第二周第二次站立会议(2016.3.29)
    爆打小组,四则运算,算法实现
    add some template for ec-final
    2014_acmicpc_shanghai_google
    matrix_world_final_2013
  • 原文地址:https://www.cnblogs.com/NuoCarter/p/14448876.html
Copyright © 2011-2022 走看看