自己写的代码都快看不懂了 qaq
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 1,SqrtN = 1e3 + 1,M = 5e5 + 1,V = 1e5 + 10;
int n,m,a[N],max_a;
int op,l,r,x;
struct block{
int l,r,Max,tag;
} b[SqrtN];
int belong[N];
int block_cnt,block_len;
struct node{
int root,cnt;
} val[V];
void clear(node &u){
u.root = u.cnt = 0;
}
struct DSU_node{
int fa,v;
} DSU[N];
int father(int x){
return x == DSU[x].fa ? x : DSU[x].fa = father(DSU[x].fa);
}
void merge(int a,int b){
node &u = val[a],&v = val[b];
if(v.root)
DSU[u.root].fa = v.root;
else{
v.root = u.root;
DSU[u.root].v = b;
}
v.cnt += u.cnt;
u.root = u.cnt = 0;
}
void push_up(int id){
b[id].Max = 0;
for(int i = b[id].l;i <= b[id].r;i++){
b[id].Max = max(b[id].Max,a[i]);
val[a[i]].cnt++;
if(val[a[i]].root)
DSU[i].fa = val[a[i]].root;
else{
DSU[i].v = a[i];
val[a[i]].root = DSU[i].fa = i;
}
}
}
void push_down(int id){
for(int i = b[id].l;i <= b[id].r;i++){
a[i] = DSU[father(i)].v;
val[a[i]].root = val[a[i]].cnt = 0;
a[i] -= b[id].tag;
}
b[id].tag = 0;
for(int i = b[id].l;i <= b[id].r;i++)
DSU[i].fa = 0;
}
void build_block(){
block_cnt = block_len = (int)sqrt(n);
for(int i = 1;i <= block_cnt;i++){
b[i].l = b[i - 1].r + 1;
b[i].r = b[i].l + block_len - 1;
}
b[block_cnt].r = n;
for(int i = 1;i <= block_cnt;i++){
for(int j = b[i].l;j <= b[i].r;j++)
belong[j] = i;
push_up(i);
b[i].tag = 0;
}
}
void make_tag(int id,int v){
if(v <= b[id].Max - b[id].tag - v){
for(int i = b[id].tag + 1;i <= b[id].tag + v;i++)
if(val[i].root)
merge(i,i + v);
b[id].tag += v;
}
else{
for(int i = b[id].Max;i > b[id].tag + v;i--)
if(val[i].root)
merge(i,i - v);
b[id].Max = min(b[id].Max,b[id].tag + v);
}
}
struct OPTION{
int op,l,r,x;
} q[M];
int ans[M];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= n;i++){
cin >> a[i];
max_a = max(max_a,a[i]);
}
build_block();
for(int i = 1;i <= m;i++)
cin >> q[i].op >> q[i].l >> q[i].r >> q[i].x;
//逐块处理
for(int i = 1;i <= block_cnt;i++){
push_up(i);
for(int j = 1;j <= m;j++){
int op = q[j].op,l = q[j].l,r = q[j].r,x = q[j].x;
if(l > b[i].r || r < b[i].l)//块与操作区间无交
continue;
if(l <= b[i].l && b[i].r <= r){//块完全包含在当前操作区间重
if(op == 1)
make_tag(i,x);
else
if(x + b[i].tag <= max_a)
ans[j] += val[x + b[i].tag].cnt;
}
else{//否则就是散块
l = max(l,b[i].l);
r = min(r,b[i].r);
if(op == 1){
for(int k = l;k <= r;k++)
if(a[k] > x)
a[k] -= x;
push_up(i);
}
else{
for(int k = l;k <= r;k++)
if(DSU[father(k)].v - b[i].tag == x)
ans[j]++;
}
}
}
}
for(int i = 1;i <= m;i++)
if(q[i].op == 2)
cout << ans[i] << '\n';
return 0;
}