题目大意:有一个数组,支持单点修改:将第 i 个位置的值变成 v。让你查询[L,R]区间内,值域在[x,y] 范围内,连续的段数,连续的段数指值相同位置连续的一段,并且连续段的长度在[L,R]内必须尽可能的长。
先对数组预处理,将连续的段缩到左端点,即新建一个数组 b, 若 a [ i ] ! = a [ i − 1 ] a[i] != a[i - 1] a[i]!=a[i−1],则 b [ i ] = 1 b[i] = 1 b[i]=1
题目转变为:查询 [ L + 1 , R ] [L + 1,R] [L+1,R],值域在 [ x , y ] [x,y] [x,y]内 1 的个数。(由于 L位置 必有贡献,因此直接查询 [ L + 1 , R ] [L + 1,R] [L+1,R]的贡献即可,对于L位置判断一下是否在值域范围内)
这个问题是一个二维偏序问题,但要支持修改,引入时间维度变成一个三维问题,可以用CDQ分治解决。
如何支持修改:细想一下修改一个位置的值除了影响自己这个位置的值外,只会影响后面一个位置的值,或者由0变成1,或者由1变成0。
对这两个位置的值枚举两种转变情况,然后转变为更新操作即可。
(CDQ分治做得少,思维对不上)
小结:CDQ分治的通常做法是将所有操作都变成更新操作和修改操作,这对这个操作序列按时间维度(或三维偏序的第一维)进行分治。
代码:
#include
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
#define lowbit(i) (i & (-i))
struct node{
int x,y,v,op,id;
node(int xi = 0,int yi = 0,int vi = 0,int pi = 0,int di = 0) {
x = xi; y = yi; op = pi; id = di;
v = vi;
}
bool operator < (const node & rhs) const {
return id < rhs.id;
}
}qes[maxn],tmp[maxn];
int cnt,n,m,a[maxn];
int val[maxn],ans[maxn];
void upd(int x,int v) {
for(; x < maxn; x += lowbit(x))
val[x] += v;
}
int qry(int x) {
int ans = 0;
for(; x; x -= lowbit(x))
ans += val[x];
return ans;
}
void cdq(int l,int r) {
if(l == r) return ;
int mid = l + r >> 1;
cdq(l,mid);cdq(mid + 1,r);
int top = 0;
for(int i = l,j = mid + 1; i <= mid || j <= r;) {
if(i <= mid && (j > r || qes[i].x <= qes[j].x)) {
if(qes[i].op == 1) upd(qes[i].y,qes[i].v);
tmp[++top] = qes[i++];
} else {
if(qes[j].op == 2) {
ans[qes[j].id] += qry(qes[j].y);
}
if(qes[j].op == 3) {
ans[qes[j].id] -= qry(qes[j].y);
}
tmp[++top] = qes[j++];
}
}
for(int i = l; i <= mid; i++)
if(qes[i].op == 1) upd(qes[i].y,-qes[i].v);
for(int i = l; i <= r; i++)
qes[i] = tmp[i - l + 1];
}
int main() {
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) {
scanf("%d",&a[i]);
if(a[i] != a[i - 1])
qes[++cnt] = node(i,a[i],1,1,0);
}
int tot = 0;
for(int i = 1; i <= m; i++) {
int op,x1,y1,x2,y2;
scanf("%d",&op);
if(op == 1) {
scanf("%d%d",&x1,&y1);
if(a[x1] == y1) continue;
if(a[x1] != a[x1 - 1])
qes[++cnt] = node(x1,a[x1],-1,1,0);
if(x1 < n && a[x1 + 1] != a[x1])
qes[++cnt] = node(x1 + 1,a[x1 + 1],-1,1,0);
a[x1] = y1;
if(a[x1] != a[x1 - 1])
qes[++cnt] = node(x1,a[x1],1,1,0);
if(x1 < n && a[x1 + 1] != a[x1])
qes[++cnt] = node(x1 + 1,a[x1 + 1],1,1,0);
} else {
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
tot++;
if(a[x1] <= y2 && a[x1] >= x2) ans[tot]++;
qes[++cnt] = node(x1,x2 - 1,0,2,tot);
qes[++cnt] = node(y1,y2,0,2,tot);
qes[++cnt] = node(x1,y2,0,3,tot);
qes[++cnt] = node(y1,x2 - 1,0,3,tot);
}
}
cdq(1,cnt);
for(int i = 1; i <= tot; i++)
printf("%d\n",ans[i]);
}