题意
给出一个长为的数列,以及
个操作,操作涉及区间询问等于一个数
的元素,并将这个区间的所有元素改为
。
思路
我们这里用flag标志数组,其作用类似于之前的lazy数组,如果,那么代表这一块还没有被整体赋值,如果
,那么代表这一块是整体赋值了的,如果flag[i]==c,那么代表这一块都是c,那么ans+=block(块的长度);如果flag[i]!=c,那么就更新为c,ans不变化。
对于不完整块,我们首先看flag是否更改过,如果更改过,那我们首先先reset一下,reset的作用是将这一块暴力赋值为flag存的数,然后再在[l,r]的区间内暴力询问c、修改c。
代码
#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N = 200007;
const int M = 10007;
int l[N],r[N],block,num,belong[N],n,x,y;
int a[N],lazy[N],b[N],sum[N],mul[N],flag[N];
inline void build()
{
block=sqrt(n);
num=n/block;if (n%num) num++;
for (int i=1;i<=num;i++)
l[i]=(i-1)*block+1,r[i]=i*block;
r[num]=n;
for (int i=1;i<=n;i++)
belong[i]=(i-1)/block+1;
for (int i=1;i<=num;i++)
flag[i]=-1;
//开始全部为-1
}
inline void reset(int x)
{
int o=belong[x];
for (int i=l[o];i<=r[o];i++)
a[i]=flag[o];
flag[o]=-1;
//flag已经全部给该块,已经没有用了
}
inline int ask(int x,int y,int c)
{
int ans=0;
if (belong[x]==belong[y])
{
if (flag[belong[x]]!=-1) reset(x);
for (int i=x;i<=y;i++)
{
if (a[i]==c) ans++;
a[i]=c;
}
//暴力求解
return ans;
}
if (flag[belong[x]]!=-1) reset(x);
for (int i=x;i<=r[belong[x]];i++)
{
if (a[i]==c) ans++;
a[i]=c;
}
if (flag[belong[y]]!=-1) reset(y);
for (int i=l[belong[y]];i<=y;i++)
{
if (a[i]==c) ans++;
a[i]=c;
}
for (int i=belong[x]+1;i<belong[y];i++)
{
if (flag[i]!=-1)
{
if (flag[i]==c) ans+=block;
}
else
{
for (int j=l[i];j<=r[i];j++)
{
if (a[j]==c) ans++;
}
//没修改过的用暴力求解
}
flag[i]=c;
//这一整块都是c
}
return ans;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
IOS
int m;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i];
}
build();
for (int k=1;k<=n;k++)
{
int l,r,op;
int c;
cin>>l>>r>>c;
cout<<ask(l,r,c)<<endl;
}
return 0;
}