zoukankan      html  css  js  c++  java
  • 让菜鸡讲一讲莫队(带修改)

    传说中,莫队算法能解决一切区间处理问题

    这是一个优雅的暴力

    那么我们再看一道题


    [国家集训队]数颜色

    膜膜购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答膜膜的提问。膜膜会像你发布如下指令:

    1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

    2、 R P Col 把第P支画笔替换为颜色Col。

    为了满足膜膜的要求,你知道你需要干什么了吗?


    我™当然知道要干什么了

    这个比上次那个题多了修改操作!普通莫队已经派不上用场了!

    然而普通莫队和带修改莫队没什么区别

    当时提莫莫涛大佬发明了莫队之后,

    因为有不能修改的debuff,

    引起了后人的不爽,

    于是后人就发明了带修改莫队

    具体来说,带修改莫队与普通莫队有这个不同:

    除了l,r两个指针之外,还增加了指针t

    这个指针的含义是当前序列是在第t次修改后的状态

    同时每个询问也要多记一个东西,就是这个是在第几次修改发生后询问的。

    那么询问的排序方法需要改变:

    inline const int operator < (const trouble &b)const
        {if(cua==b.cua)return r==b.r?t<b.t:r<b.r;return cua<b.cua;}
    "即先比较l的块,再比较r,再比较时间"
    

    还要在原来的add,del的基础上多写一个函数,我把它叫做时光机(雾

    void tmc(int now,int a)
    {
        if(q[a].l<=ch[now].d && ch[now].d<=q[a].r)
        {
            if(--cnt[v[ch[now].d]]==0)num--;
            if(cnt[ch[now].to]++==0)num++;
        }
        swap(v[ch[now].d],ch[now].to);
    }
    

    它的作用是把序列的状态变成第now次之后,

    同时修改计数君cnt和答案num。

        if(q[a].l<=ch[now].d && ch[now].d<=q[a].r)
    

    现在这次修改的地方是ch[now].d,那么只有它在l与r之间的时候才会对cnt产生影响

            if(--cnt[v[ch[now].d]]==0)num--;
            if(cnt[ch[now].to]++==0)num++;
    

    修改cnt和num

        swap(v[ch[now].d],ch[now].to);
    

    把当前颜色和目标颜色交换

    为什么是交换?

    假设这是t现在的状态

       t
    1234567... <timeline>
    

    如果现在要把时间变成第5次修改之后,

        t
    1234567... <timeline>
    

    t到达了5,执行一次tmc(5,...),会把修改的那里交换一次;

    如果现在又要把时间返回到第4次修改之后,

       t
    1234567... <timeline>
    

    t离开了5,执行一次tmc(5,...),会把修改的那里交换回来


    那么这里是[国家集训队]数颜色的代码,

    这也可以作为带修改莫队的模板了。

    #include<bits/stdc++.h>
    using namespace std;
    inline int gotcha()
    {
        register int a=0,b=1,c=getchar();
        while(!isdigit(c))b^=c=='-',c=getchar();
        while(isdigit(c))a=(a<<3)+(a<<1)+c-48,c=getchar();
        return b?a:-a;
    }
    const int _ = 10002 , __ = 1000002 , teemo = 133;
    struct trouble
    {
        int l,r,cua,num,t;
        inline const int operator < (const trouble &b)const
        {if(cua==b.cua)return r==b.r?t<b.t:r<b.r;return cua<b.cua;}
    }q[_];
    struct changes{int d,to;}ch[_];
    int n,m,v[_],cnt[__]={0},num=0,ans[_],qc=0,cc=0;
    void add(int d){if(cnt[d]++==0)num++;}void del(int d){if(--cnt[d]==0)num--;}
    void tmc(int now,int a)
    {
        if(q[a].l<=ch[now].d && ch[now].d<=q[a].r)
        {if(--cnt[v[ch[now].d]]==0)num--;if(cnt[ch[now].to]++==0)num++;}
        swap(v[ch[now].d],ch[now].to);
    }
    int main()
    {
        register int i,j,k,l,r,t;
        register char op[3];
        n=gotcha(),m=gotcha();
        for(i=1;i<=n;i++)v[i]=gotcha();
        for(i=1;i<=m;i++)
        {
            scanf("%s",op),j=gotcha(),k=gotcha();
            if(op[0]=='Q')q[++qc].l=j,q[qc].r=k,q[qc].cua=q[qc].l/teemo,q[qc].num=qc,q[qc].t=cc;
            else ch[++cc].d=j,ch[cc].to=k;
        }
        sort(q+1,q+qc+1);
        l=1,r=0,t=0;
        for(i=1;i<=qc;i++)
        {
            while(l<q[i].l)del(v[l++]);while(l>q[i].l)add(v[--l]);
            while(r<q[i].r)add(v[++r]);while(r>q[i].r)del(v[r--]);
            while(t<q[i].t)tmc(++t,i);while(t>q[i].t)tmc(t--,i);
            ans[q[i].num]=num;
        }
        for(i=1;i<=qc;i++)printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    利用HashSet去重
    互联网春天来了吗?
    了解一下ECMA标准提案的几个阶段(stagex)
    peerDependencies WARNING 警告剖析
    React Error 无法分配为只读函数"类"的属性名称
    JavaScript 经典代码大全
    Javascript 操作select控件大全(新增、修改、删除、选中、清空、判断存在等)
    父页面与子页面传数据(脚本传数据)
    ASP.NET程序中常用的三十三种代码
    将GridView导出到Excel并防止内容乱码
  • 原文地址:https://www.cnblogs.com/finder-iot/p/8409686.html
Copyright © 2011-2022 走看看