bzoj 2120 数颜色(可持久化莫队)

题意:

思路:

第一次写带修莫队,感觉还是比较简单的,相对于普通莫队,带修莫队主要是加了一个时间标志。大致思路就是,因为区间内的东西要修改,那就干脆继续暴力的修改,把[L,R]的转移,看成[L,R,T]的转移,依旧是利用排序进行优化,可以说带修莫队依旧是个暴力的优化。
不过,这题有一个疑点,就是在查看许多的博客里面,对于带修莫队,都说block为 n23 n 2 3 时带修莫队速度达到最优,为O( n53 n 5 3 )。理论值的确是这样,可是在这道题目里面,实际写起来把block写成 n n n23 n 2 3 快300ms以上

错误及反思:

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1000010;
int pos[N],arr[N],ans[N],last[N];
int times[N];
int n,m,qt,ct,now;
struct Query
{
    int l,r,id,tim;
}q[N];
struct C
{
    int pre,pos,to;
}c[N];
bool cmp(Query a,Query b){
    if(pos[a.l]!=pos[b.l])
        return a.l<b.l;
    else if(pos[a.r]!=pos[b.r])
        return a.r<b.r;
    return a.tim<b.tim;
}

void change(int x,int y){
    int temp=times[x];
    times[x]+=y;
    if(temp==1&&times[x]==0)
        now--;
    else if(temp==0&&times[x]==1)
        now++;
}
int main(){
    scanf("%d%d",&n,&m);
    int block=pow(n,0.66666);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
        last[i]=arr[i];
        pos[i]=i/block;
    }
    qt=0,ct=0,now=0;
    for(int i=0;i<m;i++)
    {
        char temp[5];
        scanf("%s",temp);
        if(temp[0]=='Q'){
            scanf("%d%d",&q[qt].l,&q[qt].r);
            q[qt].id=qt;
            q[qt++].tim=ct;
        }
        else
        {
            scanf("%d%d",&c[ct].pos,&c[ct].to);
            c[ct].pre=last[c[ct].pos];
            last[c[ct].pos]=c[ct++].to;
        }
    }
    sort(q,q+qt,cmp);
    for(int i=0,l=1,r=0,t=0;i<qt;i++)
    {

        for(;t<q[i].tim;t++)
        {
            int t1=times[c[t].pre];
            int t2=times[c[t].to];
            if(c[t].pos>=l&&c[t].pos<=r)
            {
                times[c[t].pre]--;times[c[t].to]++;
            }
            if(t1==1&&times[c[t].pre]==0)
                now--;
            else if(t1==0&&times[c[t].pre]==1)
                now++;

            if(t2==1&&times[c[t].to]==0)
                now--;
            else if(t2==0&&times[c[t].to]==1)
                now++;

            arr[c[t].pos]=c[t].to;
        }
        for(;t>q[i].tim;t--)
        {
            int t1=times[c[t-1].pre];
            int t2=times[c[t-1].to];
            if(c[t-1].pos>=l&&c[t-1].pos<=r)
            {
                times[c[t-1].to]--;times[c[t-1].pre]++;
            }
            if(t1==1&&times[c[t-1].pre]==0)
                now--;
            else if(t1==0&&times[c[t-1].pre]==1)
                now++;

            if(t2==1&&times[c[t-1].to]==0)
                now--;
            else if(t2==0&&times[c[t-1].to]==1)
                now++;
            arr[c[t-1].pos]=c[t-1].pre;
        }
        for(;l<q[i].l;l++)
            change(arr[l],-1);
        for(;l>q[i].l;l--)
            change(arr[l-1],1);
        for(;r<q[i].r;r++)
            change(arr[r+1],1);
        for(;r>q[i].r;r--)
            change(arr[r],-1);
        ans[q[i].id]=now;
    }
    for(int i=0;i<qt;i++)
        printf("%d\n",ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值