zoukankan      html  css  js  c++  java
  • codeforce 896E

    原题链接

    题目大意:

     给你一个序列,要求维护两种操作:

      1,l,r,x:   在l到r这个区间将所有 值大于X的数减X

      2, l,r,x  在l到r这个区间统计值等于X的数的个数。

      N(序列长度<=10^5),max(a)(序列中的最大值<=10^5).

      一道神题。

       我们首先应该想到用数据结构优化,但是标记下传至底之前我们不好统计答案。

       我们选择分块。

       我们考虑如何对一整块进行1操作。

       我们不妨对每一个块都统计其有几个X(X从1至10^5),并把值相同的元素串起来(用并查集维护)。

       我们对1操作进行分析,我们发现每一次操作都会使极差减小,我们很难在严格的O(1)内维护1操作,那么我们可以通过摊还分析,让每次极差减小1的操作时间复杂度达到O(1)。

      我们分情况讨论,若极差>=2x,那么我们就让最小的X个加上X,打上-X的懒标记,这个时候极差减少了X。

      若极差<2X,我们让最大的那几个减X就好,这时候我们做了min(V,极差-x)次,极差小了min(V,极差-x)。

      那么,我们就做好了。要更新边块(两侧的块)时,我们暴力修改,暴力重构就好了。

    #pragma GCC optimize("-O3")
    #include<bits/stdc++.h>
    #define sight(c) ('0'<=c&&c<='9')
    #define SIZ 254
    #define OTK 407
    #define Re register
    #define N 100607
    #define fp puts
    #define l(x) (x*SIZ-SIZ+1)
    #define r(x) (x*SIZ)
    inline void read(int &x){
        static char c;
        for (c=getchar();!sight(c);c=getchar());
        for (x=0;sight(c);c=getchar())x=x*10+c-48;
    }
    void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);}
    inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('
    '); }
    using namespace std;
    struct RR{int num,root;}V[OTK][N];
    int pre[N],pos[N],a[N],ma[N],n,m,be[N],op,l,r,v,p,q,ans,lz[N];
    inline int fa(int x){
        while (x^pre[x]) x=pre[x]=pre[pre[x]];  return x;
    }
    inline void push(int x) {
        for (Re int i=l(x);i<=r(x);i++) 
         a[i]=pos[fa(i)],V[x][a[i]].root=V[x][a[i]].num=0,a[i]-=lz[x];
        for (int i=l(x);i<=r(x);i++) pre[i]=0; lz[x]=0;
    }
    inline void reb(int x){
        ma[x]=0;
        for (Re int i=l(x);i<=r(x);i++) {
            if (a[i]>ma[x]) ma[x]=a[i];
            V[x][a[i]].root?pre[i]=V[x][a[i]].root:
            (pos[i]=a[i],V[x][a[i]].root=i,pre[i]=i);
            V[x][a[i]].num++;
        }
    }
    RR *A,*B;
    void play(int x,int a,int b){
        A=&V[x][a]; B=&V[x][b];
        B->root?pre[A->root]=B->root:(B->root=A->root,pos[A->root]=b);
        B->num+=A->num,A->num=A->root=0;
    }
    inline void det(intx,int v){
    int &p=lz[x] ,&q=ma[x];
        if ((v<<1)<=q-p) {
            for (Re int i=p+1;i<=p+v;i++)
             if (V[x][i].root) play(x,i,i+v);
            p+=v;
        } else {
            for (Re int i=q;i>p+v;i--)
              if (V[x][i].root) play(x,i,i-v);
            q=min(q,p+v);
        }
    }
    int main () {
        read(n); read(m);
        for (Re int i=1;i<=n;i++) 
         read(a[i]),be[i]=(i-1)/SIZ+1;
        for (Re int i=1;i<=be[n];i++) reb(i);
        while (m--) {
            read(op); read(l); read(r); read(v);
            switch (op) {
                case 1: p=be[l]; q=be[r];
                  if (p^q) {
                        push(p); push(q);
                        for (Re int i=l;i<=r(p);i++) if (a[i]>v) a[i]-=v;
                        for (Re int i=l(q);i<=r;i++) if (a[i]>v) a[i]-=v;
                        for (Re int i=p+1;i<q;i++) 
                         det(i,v);
                        reb(p); reb(q);
                  } else {
                       push(p);
                       for (Re int i=l;i<=r;i++) if (a[i]>v) a[i]-=v;
                       reb(p);
                  }
                break;
                case 2: p=be[l]; q=be[r]; ans=0;
                  if (p^q) {
                      for (Re int i=l;i<=r(p);i++) if (pos[fa(i)]-lz[p]==v) ans++;
                      for (Re int i=l(q);i<=r;i++) if (pos[fa(i)]-lz[q]==v) ans++;
                      for (Re int i=p+1;i<q;i++)
                        if (v+lz[i]<N) ans+=V[i][v+lz[i]].num; 
                    }else 
                     for (Re int i=l;i<=r;i++) if (pos[fa(i)]-lz[p]==v) ans++;
                   writeln(ans);
                break;
            }
        }
    }

    update :在洛谷也发现了这题,又交了一发,T且M,出题人在洛谷上只开了1s,128M,实在是幽(sang)默(xin)至(bing)极(kuang)。吓的我赶紧吧int换成unsigned char。

    #pragma GCC optimize("-O3")
    #include<bits/stdc++.h>
    #define sight(c) ('0'<=c&&c<='9')
    #define SIZ 253
    #define OTK 407
    #define Re register
    #define N 100607
    #define fp puts
    #define l(x) (x*SIZ-SIZ+1)
    #define r(x) (x*SIZ)
    inline void read(int &x){
        static char c;
        for (c=getchar();!sight(c);c=getchar());
        for (x=0;sight(c);c=getchar())x=x*10+c-48;
    }
    void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);}
    inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('
    '); }
    using namespace std;
    struct RR{unsigned char num,root;}V[OTK][N];
    int pre[N],pos[N],a[N],ma[N],n,m,be[N],op,l,r,v,p,q,ans,lz[N];
    inline int fa(int x){
        while (x^pre[x]) x=pre[x]=pre[pre[x]];  return x;
    }
    inline void push(int x) {
        for (Re int i=l(x);i<=r(x);i++) 
         a[i]=pos[fa(i)],V[x][a[i]].root=V[x][a[i]].num=0,a[i]-=lz[x];
        for (int i=l(x);i<=r(x);i++) pre[i]=0; lz[x]=0;
    }
    inline void reb(int x){
        ma[x]=0;
        for (Re int i=l(x);i<=r(x);i++) {
            if (a[i]>ma[x]) ma[x]=a[i];
            V[x][a[i]].root?pre[i]=V[x][a[i]].root+l(x)-1:
            (pos[i]=a[i],V[x][a[i]].root=i-l(x)+1,pre[i]=i);
            V[x][a[i]].num++;
        }
    }
    RR *A,*B;
    void play(int x,int a,int b){
        A=&V[x][a]; B=&V[x][b];
        B->root?pre[A->root+l(x)-1]=B->root+l(x)-1:(B->root=A->root,pos[A->root+l(x)-1]=b);
        B->num+=A->num,A->num=A->root=0;
    }
    inline void det(int x,int v){
        int &p=lz[x] ,&q=ma[x];
        if ((v<<1)<=q-p) {
            for (Re int i=p+1;i<=p+v;i++)
             if (V[x][i].root) play(x,i,i+v);
            p+=v;
        } else {
            for (Re int i=q;i>p+v;i--)
              if (V[x][i].root) play(x,i,i-v);
            q=min(q,p+v);
        }
    }
    int main () {
        read(n); read(m);
        for (Re int i=1;i<=n;i++) 
         read(a[i]),be[i]=(i-1)/SIZ+1;
        for (Re int i=1;i<=be[n];i++) reb(i);
        while (m--) {
            read(op); read(l); read(r); read(v);
            switch (op) {
                case 1: p=be[l]; q=be[r];
                  if (p^q) {
                        push(p); push(q);
                        for (Re int i=l;i<=r(p);i++) if (a[i]>v) a[i]-=v;
                        for (Re int i=l(q);i<=r;i++) if (a[i]>v) a[i]-=v;
                        for (Re int i=p+1;i<q;i++) 
                         det(i,v);
                        reb(p); reb(q);
                  } else {
                       push(p);
                       for (Re int i=l;i<=r;i++) if (a[i]>v) a[i]-=v;
                       reb(p);
                  }
                break;
                case 2: p=be[l]; q=be[r]; ans=0;
                  if (p^q) {
                      for (Re int i=l;i<=r(p);i++) if (pos[fa(i)]-lz[p]==v) ans++;
                      for (Re int i=l(q);i<=r;i++) if (pos[fa(i)]-lz[q]==v) ans++;
                      for (Re int i=p+1;i<q;i++)
                        if (v+lz[i]<N) ans+=V[i][v+lz[i]].num; 
                    }else 
                     for (Re int i=l;i<=r;i++) if (pos[fa(i)]-lz[p]==v) ans++;
                   writeln(ans);
                break;
            }
        }
    }

      

      

  • 相关阅读:
    vim 插件之commentary
    vim-进入插入模式快捷键
    adb logcat 使用
    操作excel脚本练习
    python-openpyxl安装
    python-excel操作之xlrd
    adb-端口被占用解决办法(win)
    打不开微信分享的链接
    在BUG分支下创建分支,开发后合并到bus分支
    css缓存问题
  • 原文地址:https://www.cnblogs.com/rrsb/p/8323560.html
Copyright © 2011-2022 走看看