欲望以提升热忱,毅力以磨平高山!|

XichenOC

园龄:1个月粉丝:4关注:0

2025-01-20 19:35阅读: 7评论: 0推荐: 0

莫队-带修莫队(学习笔记)

P1903 [国家集训队] 数颜色 / 维护队列

简述:

我们发现莫队的操作是离线的,且只能经行查询工作,但如果遇到需要修改的题目该如何办。这时候就需要用带修莫队来维护了,带修莫队也是一种离线算法,复杂度也约等于 \(O(n\sqrt n)\)

原理:

我们可以在维护一个修改的时间刻。也就是修改的时间给储存下来,这样在我们移动区间后将现在的时间移到对应的时间刻,同时对修改的内容进行参数的调整即可。在查询是维护一个当前时间,若时间过了就回退,若还没到就增加

为了保证若时间回退修改的值复原,那我们可以在修改时将修改值和当前值经行交换,这样在回退时修改就是变回原样

void change(int x){
    if(u[x].id>=l && u[x].id<=r){
        del(a[u[x].id]);
        add(u[x].val);
    }
    swap(a[u[x].id],u[x].val);
}

需要注意的是,由于有了时间的增减,普通的 \(\sqrt n\) 的块大小不太适用,一般来说 \(n^{\frac{2}{3}}\)或者以下大小:

int len=10;
while(1ll*len*len*len<=1ll*n*n*3)len++;

完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N=135000;
int a[N],block[N],ans[N],vis[N*10];
struct query{
    int l,r,t,id;
}q[N];
struct update{
    int id,val;
}u[N];
bool cmp(query x,query y){
    if(block[x.l]!=block[y.l])return x.l<y.l;
	if(block[x.r]!=block[y.r])return (block[x.l]&1)?(x.r<y.r):(x.r>y.r);
	return x.t<y.t;

}
int sum,l,r,now;
void add(int x){
    if(!vis[x])sum++;
    vis[x]++;
}
void del(int x){
    vis[x]--;
    if(!vis[x])sum--;
}
void change(int x){
    if(u[x].id>=l && u[x].id<=r){
        del(a[u[x].id]);
        add(u[x].val);
    }
    swap(a[u[x].id],u[x].val);
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    int len=10;
    while(1ll*len*len*len<=1ll*n*n*3)len++;
    for(int i=1;i<=n;i++){
        block[i]=i/len;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int cntq=0,cntu=0;
    for(int i=1;i<=m;i++){
        char op;
        int l,r;
        cin>>op>>l>>r;
        if(op=='Q'){
            q[++cntq]={l,r,cntu,cntq};
        }
        else{
            u[++cntu]={l,r};
        }
        
    }
    sort(q+1,q+cntq+1,cmp);
    l=1,r=0;
    now=0;
    for(int i=1;i<=cntq;i++){
        int ll=q[i].l,rr=q[i].r;    
        while(now<q[i].t)change(++now);
        while(now>q[i].t)change(now--);
        while(l<ll)del(a[l++]);
        while(l>ll)add(a[--l]);
        while(r<rr)add(a[++r]);
        while(r>rr)del(a[r--]);
        ans[q[i].id]=sum;
    }
    for(int i=1;i<=cntq;i++){
        printf("%d\n",ans[i]);
    }
}

本文作者:XichenOC

本文链接:https://www.cnblogs.com/XichenOC/p/18682412

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   XichenOC  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起