洛谷P3616 富金森林公园

@Pelom  October 12, 2021

题意

对于一个数列,有$2$种操作:

  • $1 \ x$ 询问$\ge x$的连续段的个数
  • $2 \ i \ x$ 将$a_i$的值修改为$x$

数据范围:$1 \le n,m \le 200000,1 \le a_i,x \le 10^9$

题解

首先对于一个询问考虑:将$\ge x$的数定义为$1$,$< x$的数定义为$0$;那么一个段的构成应为$$011 \dots 110$$即一个$01$+若干$11$+一个$10$,那么段的个数即为$01$或$10$的个数
如何统计这个数呢?记$\max(a[i],a[i-1])=1$的个数为$m$,$\min(a[i],a[i-1])=1$的个数为$n$,答案即为$\frac{n-m}{2}$
为什么呢?$m$代表$01,11,10$的数量,$n$代表$11$的数量,自然$n-m$就代表$01,10$的数量,而$01,10$成对出现,答案即为$\frac{n-m}{2}$
那么,$11$的贡献就为$1$,$01$或$10$的贡献就为$-1$
再来考虑多个询问:对于较大的$x$为$1$,那么对于较小的$x$显然也为$1$;所以我们在值域上建树状数组(虽然有$10^9$,但可以离散化),不过由于我们需要的是$\ge x$的信息,所以反着来
每次修改将初始的影响取消掉,修改值后再增添影响

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=200000+10;
int n,m;
int a[N];
struct Query{
    int op,i,x;
} q[N];
int tot;
int b[N<<1],T[N<<1];
inline int lowbit(int x){
    return x&-x;
}
inline void update(int p,int k){
    p=tot-p+1;
    for(;p<=tot;p+=lowbit(p))
        T[p]+=k;
}
inline int query(int p){
    p=tot-p+1;
    int res=0;
    for(;p;p-=lowbit(p))
        res+=T[p];
    return res;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[++tot]=a[i];
    }
    for(int i=1;i<=m;i++){
        scanf("%d",&q[i].op);
        if(q[i].op==2)
            scanf("%d",&q[i].i);
        scanf("%d",&q[i].x);
        b[++tot]=q[i].x;
    }
    sort(b+1,b+tot+1);
    tot=unique(b+1,b+tot+1)-b-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(b+1,b+tot,a[i])-b;
    for(int i=1;i<=m;i++)
        q[i].x=lower_bound(b+1,b+tot+1,q[i].x)-b;
    for(int i=0;i<=n;i++){
        update(max(a[i],a[i+1]),+1);
        update(min(a[i],a[i+1]),-1);
    }
    for(int i=1;i<=m;i++){
        if(q[i].op==1)
            printf("%d\n",query(q[i].x)>>1);
        else{
            int j=q[i].i;
            update(max(a[j],a[j+1]),-1);
            update(max(a[j],a[j-1]),-1);
            update(min(a[j],a[j+1]),+1);
            update(min(a[j],a[j-1]),+1);
            a[j]=q[i].x;
            update(max(a[j],a[j+1]),+1);
            update(max(a[j],a[j-1]),+1);
            update(min(a[j],a[j+1]),-1);
            update(min(a[j],a[j-1]),-1);
        }
    }
    return 0;
}

添加新评论