#6284. 数列分块入门 8
题目描述
给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间询问等于一个数 ccc 的元素,并将这个区间的所有元素改为 ccc。
输入格式
第一行输入一个数字 nnn。
第二行输入 nnn 个数字,第 i 个数字为 aia_iai,以空格隔开。
接下来输入 nnn 行询问,每行输入三个数字 lll、rrr、ccc,以空格隔开。
表示先查询位于 [l,r][l,r][l,r] 的数字有多少个是 ccc,再把位于 [l,r][l,r][l,r] 的数字都改为 ccc。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 4
1 3 1
1 4 4
1 2 2
1 4 2
样例输出
1
1
0
2
数据范围与提示
对于 100% 100\%100% 的数据,1≤n≤100000,−231≤others 1 leq n leq 100000, -2^{31} leq mathrm{others}1≤n≤100000,−231≤others、ans≤231−1 mathrm{ans} leq 2^{31}-1ans≤231−1。
维护区间是否是连续的相同值
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define maxn 100010 using namespace std; int n,m,block,a[maxn],tag[maxn],pos[maxn]; bool cover[maxn]; int findl(int id){return (id-1)*block+1;} int findr(int id){return min(id*block,n);} void reset(int id,int l,int r,int v1,int v2){ for(int i=findl(id);i<l;i++)a[i]=v1; for(int i=l;i<=r;i++)a[i]=v2; for(int i=r+1;i<=findr(id);i++)a[i]=v1; cover[id]=0; } int count(int l,int r,int v){ int res=0; for(int i=l;i<=r;i++){ if(a[i]==v)res++; else a[i]=v; } return res; } int get(int l,int r,int v){ if(cover[pos[l]]){ if(tag[pos[l]]==v)return r-l+1; else reset(pos[l],l,r,tag[pos[l]],v); } else return count(l,r,v); return 0; } int query(int l,int r,int v){ int res=get(l,min(findr(pos[l]),r),v); if(pos[l]!=pos[r])res+=get(findl(pos[r]),r,v); for(int i=pos[l]+1;i<=pos[r]-1;i++){ if(cover[i]){ if(tag[i]==v)res+=pos[l]==pos[n]?m:block; else tag[i]=v; } else { res+=count(findl(i),findr(i),v); cover[i]=1; tag[i]=v; } } return res; } int main(){ scanf("%d",&n); block=sqrt(n); for(int i=1;i<=n;i++){ pos[i]=(i-1)/block+1; scanf("%d",&a[i]); } m=n-(pos[n]-1)*block; int l,r,c; for(int i=1;i<=n;i++){ scanf("%d%d%d",&l,&r,&c); printf("%d ",query(l,r,c)); } return 0; }