码迷,mamicode.com
首页 > 其他好文 > 详细

codeforce 896E

时间:2018-01-21 12:30:24      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:code   getchar   cas   操作   switch   puts   amp   ace   严格   

原题链接

题目大意:

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

  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(\n); }
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(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;
        }
    }
}

 

 

  

  

codeforce 896E

标签:code   getchar   cas   操作   switch   puts   amp   ace   严格   

原文地址:https://www.cnblogs.com/rrsb/p/8323560.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!