Loading

SP30906

这是一道带修莫队。

我们都知道一般的莫队是不带修的,其原理就是把所有的询问先排序然后统一处理。

但是加入修改之后,可能某些询问中穿插了修改,导致我们无法判断一个区间在被询问之前是否被修改过。

所以我们可以对于询问和修改操作记录一个时间,并将它的在一个询问操作执行前执行掉它这个时间之前的所有修改操作。

当然这也只限于单点修改。

也可以看这里,对于带修莫队有更详细的解释。

#include<cmath>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define maxn 200100
#define INF 0x3f3f3f3f
//#define int long long

using namespace std;

int n,m,len,L=2,R=1,tot,all,cntq,cntc,Now,Ans; 
int a[maxn],ans[maxn],cnt[maxn],b[maxn];
struct question{int l,r,t,now;}q[maxn];
struct change{int pos,val;}c[maxn];
 
int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
    return s*w;
}

bool cmp(question a,question b){
    return (a.l/len)^(b.l/len)?a.l<b.l:(a.r/len)^(b.r/len)?a.r<b.r:a.t<b.t;
}

void Add(int x){
    Ans-=(cnt[x]==1);
    Ans+=(++cnt[x]==1);
}

void Del(int x){
    Ans-=(cnt[x]==1);
    Ans+=(--cnt[x]==1);
}

void Query(int x,int i){
    if(q[x].l<=c[i].pos&&q[x].r>=c[i].pos){
        Del(a[c[i].pos]),Add(c[i].val);
    }
    swap(a[c[i].pos],c[i].val);
}

signed main(){
    n=read();m=read();len=pow(n,2.0/3);
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1,opt;i<=m;i++){
        opt=read();
        if(opt==1) c[++cntc].pos=read()+1,c[cntc].val=read();
        else q[++cntq].l=read()+1,q[cntq].r=read()+1,q[cntq].now=cntq,q[cntq].t=cntc;
    }
    sort(q+1,q+cntq+1,cmp); 
    for(int i=1;i<=m;i++){
        while(L<q[i].l) Del(a[L++]);
        while(L>q[i].l) Add(a[--L]);
        while(R<q[i].r) Add(a[++R]);
        while(R>q[i].r) Del(a[R--]);
        while(Now<q[i].t) Query(i,++Now);
        while(Now>q[i].t) Query(i,Now--);
        ans[q[i].now]=Ans;
    }
    for(int i=1;i<=cntq;i++) printf("%d\n",ans[i]);
    return 0;
}
posted @ 2021-04-25 16:39  KnightL  阅读(51)  评论(0编辑  收藏  举报