[Ynoi2018] 五彩斑斓的世界 题解
题意:要求对长度为 \(n\),值域为 \(V\) 的序列执行 \(m\) 次操作。操作一为将区间中大于 \(x\) 的数减去 \(x\),操作二为询问区间内 \(x\) 的出现次数。\(n\le 10^6,V\le 10^5,m\le 5\times 10^5\)。
我们可以用一个并查集把相同的数都划分到同一个集合里,当发生减法的时候就合并集合。操作一若是直接减的话,要对值域里大于 \(x\) 的数都判断一次其是否在当前块中出现,当 \(x\) 远小于区间最值的时候会超出时限。设当前块的最值为 \(mx\),则我们考虑平衡一下操作一,当 \(x\) 接近 \(mx\) 的时候,我们把 \([x+1,mx]\) 中所有出现过的数都和其减去 \(x\) 的集合合并,当 \(x\) 较小时,把 \([0,x]\) 中的数向加上 \(x\) 的集合合并,再标记全局减 \(x\)。这样每次操作的数都是更少的。
对于散块修改则暴力操作后,重新建立新的并查集。
由于空间限制严格,我们必须依次对每个块执行所有操作。
#include<bits/stdc++.h>
using namespace std;
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int read(){
int k=0,f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())k=(k*10+c-'0');
return k*f;
}
void write(int x){
if(x<10)putchar(x+'0');
else write(x/10),putchar(x%10+'0');
}
int n,m,t;
const int N = 1e5+10;
int a[N*10],ans[5*N];
int op[5*N],ql[5*N],qr[5*N],qx[5*N];
int fa[10*N],val[10*N],rt[N],cnt[N],mx,tag;
int find(int x) {
while(x!=fa[x])x=fa[x]=fa[fa[x]];
return x;
}
void merge(int x,int y){
if(!rt[y]){
rt[y]=rt[x];
val[rt[y]]=y;
}else{
fa[rt[x]]=rt[y];
}
cnt[y]+=cnt[x];
cnt[x]=0;rt[x]=0;
}
void solve(int l,int r){
mx=tag=0;
for(int i=l;i<=r;i++){
mx=max(a[i],mx);
if(!rt[a[i]]){
rt[a[i]]=fa[i]=i;
val[i]=a[i];
}else{
fa[i]=rt[a[i]];
}
cnt[a[i]]++;
}
for(int i=1;i<=m;i++){
if(ql[i]>r||qr[i]<l)continue;
int x=qx[i];
if(ql[i]<=l&&r<=qr[i]){
if(op[i]==1){
if(!x||mx<=x)continue;
if(2*x>=mx-tag){
for(int v=x+tag+1;v<=mx;v++){
if(rt[v])merge(v,v-x);
}
mx=min(mx,x+tag);
}else{
for(int v=x+tag;v>=tag;v--){
if(rt[v])merge(v,v+x);
}
tag+=x;
}
}else{
if(x+tag<N)ans[i]+=cnt[x+tag];
}
}else{
if(op[i]==1){
if(!x||mx<=x)continue;
for(int i=l;i<=r;i++){
a[i]=val[find(i)];
}
for(int i=l;i<=r;i++){
rt[a[i]]=cnt[a[i]]=0;
val[i]=0;fa[i]=0;
a[i]-=tag;
}
for(int j=max(l,ql[i]);j<=min(r,qr[i]);j++){
if(a[j]>x)a[j]-=x;
}
mx=tag=0;
for(int i=l;i<=r;i++){
mx=max(a[i],mx);
if(!rt[a[i]]){
rt[a[i]]=fa[i]=i;
val[i]=a[i];
}else{
fa[i]=rt[a[i]];
}
cnt[a[i]]++;
}
}else{
for(int j=max(l,ql[i]);j<=min(r,qr[i]);j++){
if(x+tag<N)ans[i]+=(val[find(j)]-tag==x);
}
}
}
}
for(int i=l;i<=r;i++){
a[i]=val[find(i)];
rt[a[i]]=cnt[a[i]]=0;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
n=read(),m=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
for(int i=1;i<=m;i++){
op[i]=read(),ql[i]=read(),qr[i]=read(),qx[i]=read();
}
t=666;
for(int i=1;i<=n;i+=t){
solve(i,min(i+t-1,n));
}
for(int i=1;i<=m;i++){
if(op[i]==2){
write(ans[i]);
putchar(endl);
}
}
return 0;
}

浙公网安备 33010602011771号