天天看點

Codeforces Round #449 (Div. 1) E. Welcome home, Chtholly

E. Welcome home, Chtholly

time limit per test3 seconds

memory limit per test512 megabytes

inputstandard input

outputstandard output

— I… I survived.

— Welcome home, Chtholly.

— I kept my promise…

— I made it… I really made it!

After several days of fighting, Chtholly Nota Seniorious miraculously returned from the fierce battle.

As promised, Willem is now baking butter cake for her.

However, although Willem is skilled in making dessert, he rarely bakes butter cake.

This time, Willem made a big mistake — he accidentally broke the oven!

Fortunately, Chtholly decided to help him.

Willem puts n cakes on a roll, cakes are numbered from 1 to n, the i-th cake needs ai seconds of baking.

Willem needs Chtholly to do m operations to bake the cakes.

Operation 1: 1 l r x

Willem asks Chtholly to check each cake in the range [l, r], if the cake needs to be baked for more than x seconds, he would bake it for x seconds and put it back in its place. More precisely, for every i in range [l, r], if ai is strictly more than x, ai becomes equal ai - x.

Operation 2: 2 l r x

Willem asks Chtholly to count the number of cakes in the range [l, r] that needs to be cooked for exactly x seconds. More formally you should find number of such i in range [l, r], that ai = x.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 105).

The second line contains n integers, i-th of them is ai (1 ≤ ai ≤ 105).

The next m lines are the m operations described above. It is guaranteed that 1 ≤ l ≤ r ≤ n and 1 ≤ x ≤ 105.

Output

For each operation of the second type, print the answer.

Examples

input

5 6

1 5 5 5 8

2 2 5 5

1 2 4 3

2 2 5 2

2 2 5 5

1 3 5 1

2 1 5 1

output

3

3

3

input

7 7

1 9 2 6 8 1 7

2 1 7 1

2 2 5 2

1 4 7 7

2 2 4 2

1 3 4 5

2 3 3 3

2 3 7 2

output

2

1

1

1

input

8 13

75 85 88 100 105 120 122 128

1 1 8 70

2 3 8 30

1 3 8 3

2 2 5 15

1 2 4 10

2 1 5 5

1 2 7 27

2 1 5 5

1 3 7 12

1 1 7 4

2 1 8 1

1 4 8 5

2 1 8 1

output

1

2

3

4

5

6

題意:給你一個數組,有兩種操作,1:把l,r之間大于x的數字減去x,2:詢問l到r之間x的數量。

做法:對于第一種操作可以把它分成兩類1:全部的數減去x,然後小于1的加上x,2:大于x的數減去x;對于一個集合來說,用L來維護這個區間的要減去的數,R維護這個區間最大的數,

并且用并查集維護相等的點,然後如果2*x>R-L,那麼久執行第1類操作,把小于L+x的數加上x,然後L加上x,如果x>R-L,那執行第二類操作,把大于x的數減去x。這樣維護的話最多進過R-L次操作,所有的數就變成相同的數了。

具體做法:分塊,每塊用并查集維護,每次把相等的數連起來,用a[x][i]維護第x塊裡面值為i的數有多少,然後查詢的時候第i塊值為y的個數就是a[x][L[x]+y],可以用head[x][i],來維護第x塊值為i的并查集的根,每次展開空間的時候隻需要把a[x][num[i]]和head[x][num[i]]重置就可以保證L[x]到R[x]區間内的a,head都是重置的。

#include<bits/stdc++.h>
using namespace std;
const int N = e5+;
const int B = ;
int fa[N],a[B][N],head[B][N],L[N],R[N],pos[N],num[N];
int Find(int x){return x == fa[x]?x:fa[x]=Find(fa[x]);}
void pushdown(int x){
    for(int i = x*B;i < x*B+B;i ++){
        num[i] = pos[Find(i)];
        a[x][num[i]] = ;
        head[x][num[i]] = -;
    }
}
void update(int x){
    R[x] = ;
    for(int i = x*B;i < x*B+B;i ++){
        R[x] = max(R[x],num[i]);
        if(head[x][num[i]] == -){
            head[x][num[i]] = i;
            pos[i] = num[i];
            fa[i] = i;
        }
        else fa[i] = head[x][num[i]];
        a[x][num[i]]++;
    }
}
void mergee(int x,int p,int q){
    if(head[x][p] != -){
        if(head[x][q] == -){
            head[x][q] = head[x][p];
            a[x][q] = a[x][p];
            pos[head[x][p]] = q;
        }
        else{
            fa[head[x][p]] = head[x][q];
            a[x][q] += a[x][p];
        }
    }
}
void solve(int l,int r,int x){
    int ll = l/B,rr = r/B;
    if(ll == rr){
        pushdown(ll);
        for(int i = l;i <= r;i ++){
            if(num[i]>L[ll]+x) num[i] -= x;
        }
        update(ll);
    }
    else{
        pushdown(ll),pushdown(rr);
        for(int i = l;i < ll*B+B;i ++){
            if(num[i] > L[ll]+x) num[i] -= x;
        }
        for(int i = rr*B;i <= r;i ++){
            if(num[i] > L[rr]+x) num[i] -= x;
        }
        update(ll),update(rr);
        for(int i = ll+;i < rr;i ++){
            if(R[i] > *x+L[i]){
                for(int j = L[i]+;j <= L[i]+x;j ++) mergee(i,j,j+x);
                L[i]+=x;
            }
            else if(R[i] > x+L[i]){
                for(int j = R[i];j > L[i]+x;j --){
                    mergee(i,j,j-x);
                }
                R[i] = x+L[i];
            }
        }
    }
}
int query(int l,int r,int x){
    int ll = l/B,rr = r/B;
    if(ll == rr){
        pushdown(ll);
        int ans = ;
        for(int i = l;i <= r;i ++)
            if(L[ll]+x == num[i]) ans ++;
        update(ll);
        return ans;
    }
    else{
        int ans = ;
        for(int i = l;i < ll*B+B;i ++){
            if(L[ll]+x == pos[Find(i)]) ans ++;
        }
        for(int i = rr*B;i <= r;i ++){
            if(L[rr]+x == pos[Find(i)]) ans ++;
        }
        for(int i = ll+;i < rr;i ++)
            if(L[i]+x <= R[i]) ans += a[i][L[i]+x];
        return ans;
    }
}

int main(){
    int n,m;
    memset(head,-,sizeof(head));
    scanf("%d %d",&n,&m);
    for(int i = ;i <= n;i ++) scanf("%d",&num[i]);
    for(int i = ;i <= n/B;i ++)
        update(i);

    for(int i = ;i <= m;i ++){
        int op,l,r,x;
        scanf("%d %d %d %d",&op,&l,&r,&x);
        if(op == ) solve(l,r,x);
        else printf("%d\n",query(l,r,x));
    }
    return ;
}