【jzoj5289】【NOIP2017提高組A組模擬8.17】【偷笑】【數據結構】

Description

berber走進機房,邊敲門邊喊:“我是嗶嗶”

CRAZY轉過頭:“我警告你,嗶嗶剛剛來過!”

“呵呵呵呵……”

這時,嗶嗶站了起來,環顧四周:“你們笑什麼?……”

巧了,發出笑聲的人都排成了一排,每個人剛開始發出的笑聲值爲a[i]的笑聲。但是有些笑聲嗶嗶是聽不出來的,他只聽得出笑聲值只包含2和3的數字,比如說什麼2333。

但是同學們還是很會秀操作的。對於操作add l r x表示l到r的同學的笑聲值同時加上x。數據保證操作完的x在2*10^4以內。

但是,嗶嗶還是很想知道哪些人在笑。對於count l r表示詢問l到r的同學中有多少個笑聲值是嗶嗶聽得出來的(就是隻由2和3組成)。

嗶嗶是很忙的,他需要坐在旁邊的你來幫他完成這個問題。

Solution

首先x是正數,在20000內只有30個數用貢獻,我們用線段樹維護每個數離最近有貢獻數多少,維護區間最小,最小有多少個,及一個最小的位置。只要最小值小於0就暴力重構那個點,移到離下一個數的距離。

code

#include<set>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j) for(int i=begin[j];i;i=next[i])
using namespace std;
int const mn=3*1e5+9,inf=1e9+7;
int n,m,a[mn],b[mn],pos[mn*4],cnt[mn*4],mi[mn*4],tag[mn*4];
void uptag(int p){
    mi[p*2]-=tag[p];
    mi[p*2+1]-=tag[p];
    tag[p*2]+=tag[p];
    tag[p*2+1]+=tag[p];
    tag[p]=0;
}
void updata(int p){
    if(mi[p*2]==mi[p*2+1]){
        pos[p]=pos[p*2];
        cnt[p]=cnt[p*2]+cnt[p*2+1];
        mi[p]=mi[p*2];
    }else{
        int tmp=(mi[p*2]<mi[p*2+1])?p*2:p*2+1;
        pos[p]=pos[tmp];
        cnt[p]=cnt[tmp];
        mi[p]=mi[tmp];
    }
}
void oper(int p,int l,int r,int u,int v){
    if((l!=r)&&tag[p])uptag(p);
    int mid=(l+r)/2;
    if(l==r){
        pos[p]=l;
        cnt[p]=1;
        mi[p]=v;
        return;
    }
    if(u<=mid)oper(p*2,l,mid,u,v);
    else oper(p*2+1,mid+1,r,u,v);
    updata(p);
}
void ope2(int p,int l,int r,int u,int v,int w){
    if((l!=r)&&tag[p])uptag(p);
    int mid=(l+r)/2;
    if((l==u)&&(r==v)){
        mi[p]-=w;
        tag[p]+=w;
        return;
    }
    if(v<=mid)ope2(p*2,l,mid,u,v,w);
    else if(mid<u)ope2(p*2+1,mid+1,r,u,v,w);
    else ope2(p*2,l,mid,u,mid,w),ope2(p*2+1,mid+1,r,mid+1,v,w);
    updata(p);
}
int qury(int p,int l,int r,int u,int v){
    if((l!=r)&&tag[p])uptag(p);
    int mid=(l+r)/2;
    if((l==u)&&(r==v)){
        return (mi[p]==0)?cnt[p]:0;
    }
    if(v<=mid)return qury(p*2,l,mid,u,v);
    else if(mid<u)return qury(p*2+1,mid+1,r,u,v);
    else return qury(p*2,l,mid,u,mid)+qury(p*2+1,mid+1,r,mid+1,v);
}
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,20000){
        int ii=i,ok=1;
        while(ii){
            if((ii%10!=2)&&(ii%10!=3)){
                ok=0;
                break;
            }
            ii/=10;
        }
        if(ok)b[++b[0]]=i;
    }
    fo(i,1,n){
        scanf("%d",&a[i]);
        int tmp;
        fo(j,1,b[0])if(b[j]>=a[i]){
            oper(1,1,n,i,b[j]-a[i]);
            tmp=j;
            break;
        }
        if(a[i]>b[b[0]])oper(1,1,n,i,inf),tmp=b[0]+1;
        a[i]=tmp;
    }
    fo(cas,1,m){
        char ch=getchar();
        while((ch!='c')&&(ch!='a'))ch=getchar();
        if(ch=='c'){
            int l,r;
            scanf("ount%d%d",&l,&r);
            printf("%d\n",qury(1,1,n,l,r));
        }else{
            int l,r,x,tmp;
            scanf("dd%d%d%d",&l,&r,&x);
            ope2(1,1,n,l,r,x);
            while(mi[1]<0){
                oper(1,1,n,tmp=pos[1],(a[pos[1]]<b[0])?b[a[pos[1]]+1]-b[a[pos[1]]]+mi[1]:inf);
                a[tmp]++;
            }
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章