Loj#6284. 数列分块入门 8
给出一个长为n的数列,以及n个操作,操作涉及区间询问等于一个数c的元素,并将这个区间的所有元素改为c。
样例输入
4
1 2 2 4
1 3 1
1 4 4
1 2 2
1 4 2
样例输出
1 1 0 2
分析:对于每一个块维护一个覆盖标记. 如果这个块被完整的覆盖了,标记记录的就是对应覆盖的值,否则就是-1.
查询的时候,对于-1的块,暴力统计,否则看块的覆盖标记是不是c就好了.
#include <bits/stdc++.h> using namespace std; const int maxn = 100010; int n,a[maxn],tag[maxn],L[maxn],R[maxn],pos[maxn],block,cnt; void pushdown(int x) { if (tag[x] == -1) return; for (int i = L[x]; i <= R[x]; i++) a[i] = tag[x]; tag[x] = -1; } int solve(int l,int r,int x) { int res = 0; if (pos[l] == pos[r]) { pushdown(pos[l]); for (int i = l; i <= r; i++) { if (a[i] == x) res++; a[i] = x; } return res; } pushdown(pos[l]); for (int i = l; i <= R[pos[l]]; i++) { if (a[i] == x) res++; a[i] = x; } pushdown(pos[r]); for (int i = L[pos[r]]; i <= r; i++) { if (a[i] == x) res++; a[i] = x; } for (int i = pos[l] + 1; i <= pos[r] - 1; i++) { if (tag[i] == -1) { for (int j = L[i]; j <= R[i]; j++) { if (a[j] == x) res++; a[j] = x; } } else if (tag[i] == x) res += block; tag[i] = x; } return res; } void print() { for (int i = 1; i <= n; i++) printf("%d ",a[i]); printf("\n"); } int main() { memset(tag,-1,sizeof(tag)); scanf("%d",&n); block = sqrt(n); for (int i = 1; i <= n; i++) { scanf("%d",&a[i]); pos[i] = (i - 1) / block + 1; } cnt = (n - 1) / block + 1; for (int i = 1; i <= cnt; i++) { L[i] = R[i - 1] + 1; R[i] = min(n,i * block); } for (int i = 1; i <= n; i++) { int l,r,c; scanf("%d%d%d",&l,&r,&c); printf("%d\n",solve(l,r,c)); } return 0; }