【[国家集训队]数颜色】

下面的同学们搞怪了

好的,话不多说,我来讲这道题时顺便就来讲讲带修莫队

不知道普通莫队是什么的请参见我之前为小Z的袜子写的博客

首先来审审题意:多个区间询问,询问[l,r]中颜色的种类数。可以单点修改颜色。

莫队可以修改???

那么我们切入正题

这类问题被称为带修莫队(可持久化莫队)。

类比到主席树,即可持久化线段树,可以引入一个“修改时间”,表示当前询问是发生在前time个修改操作后的。也就是说,在进行莫队算法时,看看当前的询问和时间指针(第三个指针,别忘了s,e)是否相符,然后进行时光倒流(向前)或者时光推移(向后)操作来维护答案。

原本sort的构造。仅靠原来的sort关键字会使得枚举每个询问都可能因为时间指针移动的缘故要移动n次,总共就n^2次,那还不如写暴力。

所以为了防止这样的事情发生,大神们()再加入第三关键字tim:

   bool cmp(Node a,Node b)
   {
        return Be[a.l]==Be[b.l]?(Be[a.r]==Be[b.r]?a.tim<b.tim:a.r<b.r):a.l<b.l;
   }

Be数组的意义是记录分块大小

上次忘说了请见谅

接着就是时间复杂度

首先,r和tim的关系就像l和r的关系一样:只有在前后者处于同块时,后者才会因排序而有序,否则sort会去满足前者,使得后者开始乱跳。

依旧像上文那样:枚举m个答案,就一个m了。设分块大小为size。

分类讨论:

①对于l指针,依旧是O(size*n)

②对于r指针,依旧是O(n*n/size)

③对于tim指针:

类比r时间复杂度的计算。我们要寻找有多少个单调段(一个单调段下来最多移动n次)。上文提到,当且仅当两个询问l在同块,r也在同块时,才会对tim进行排序。对于每一个l的块,里面r最坏情况下占据了所有的块,所以最坏情况下:有n/size个l的块,每个l的块中会有n/size个r的块,此时,在一个r块里,就会出现有序的tim。所以tim的单调段个数为:(n/size)*(n/size)。每个单调段最多移动n次。

所以,其复杂度=O((n/size)2*n)

三个指针汇总:O(sizen+n^2/size+(n/size)^2n)

当size=n*sqrt(n)时,复杂度取到最高:

O(n^(5/3))!!!

接下来是代码

#include<stdio.h>
#include<algorithm>
#include<math.h>
#define go(i,a,b) for(int i=a;i<=b;i++)
using namespace std;const int N=10005;
struct Node{
int l,r,tim,ID;
}q[N];
struct Change{
int pos,now,bef;
}c[N];
int n,m,s[N],color[1000005],t,time,now[N],size,Be[N],ans[N],Ans,l=1,r,T;
bool cmp(Node a,Node b)
{
    return Be[a.l]==Be[b.l]?(Be[a.r]==Be[b.r]?a.tim<b.tim:a.r<b.r):a.l<b.l;
}
void revise(int x,int d)
{
color[x]+=d;
if(d>0)Ans+=color[x]==1;
else if(d<0)Ans-=color[x]==0;
}
void going(int x,int d)
{
if(l<=x&&x<=r)revise(d,1),revise(s[x],-1);
s[x]=d;
}
int main(){
    scanf("%d%d",&n,&m);size=pow(n,0.666666);
    go(i,1,n)scanf("%d",&s[i]),now[i]=s[i],Be[i]=i/size+1;
    go(i,1,m){char sign;int x,y;scanf(" %c %d%d",&sign,&x,&y);
        if(sign==‘Q‘)q[++t]=(Node){x,y,time,t};
        if(sign==‘R‘)c[++time]=(Change){x,y,now[x]},now[x]=y;
    }
    sort(q+1,q+t+1,cmp);
    go(i,1,t)
    {
        while(T<q[i].tim)going(c[T+1].pos,c[T+1].now),T++;
        while(T>q[i].tim)going(c[T].pos,c[T].bef),T--;
        while(l<q[i].l)revise(s[l],-1),l++;
        while(l>q[i].l)revise(s[l-1],1),l--;
        while(r<q[i].r)revise(s[r+1],1),r++;
        while(r>q[i].r)revise(s[r],-1),r--;

        ans[q[i].ID]=Ans;
    }
    go(i,1,t)printf("%d\n",ans[i]);
return 0;
}

原文地址:https://www.cnblogs.com/66t6/p/8641359.html

时间: 2024-08-30 14:50:50

【[国家集训队]数颜色】的相关文章

国家集训队——数颜色

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col. 题解: 做这道题之前不会带修改莫队,山神学会了之后手(嘴)把手(嘴)教我打代码. 莫队算法先放下,带修改莫队是酱的:记下所有的修改,同时为每个询问加入一个时间标记,表示这个询问发生时修改到了哪一步.求解之前记录一个时间戳.每次求解一个询问时,先按普通莫队求解

[莫队] 国家集训队 数颜色(尚未完成)

题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col. 为了满足墨墨的要求,你知道你需要干什么了吗? 输入输出格式 输入格式: 第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数. 第2行N个整数,分别代表初始画笔排中第i支画笔的颜色. 第3行到第2+M行,每行分别代表墨墨会做的一件事

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

毒瘤数据卡普通莫队!! 这道题跟普通的莫队题目差不多,但是多了一个修改操作. 所以带修莫队就横空出世了. 普通莫队记录左端点和右端点,那么这里就再记录一个时间轴,表示当时已经执行过几次修改. 之后莫队模板就有六个while,前四个是一样的. 最后两个判断当前修改次数和目标修改次数的关系.这个就是灵魂了. 重点看这个时间轴上的修改吧. void change(int idx, int i) { if(q[i].l <= c[idx].p && c[idx].p <= q[i].r

莫队学习总结 &amp;&amp; P1903 [国家集训队]数颜色 / 维护队列

关于时间复杂度 对于多维莫队的复杂度差不多为\(O(n^{\frac{2k-1}{k}})\) 摘自zhihu大佬 奇偶分类优化 return a.l == b.l ? (a.l & 1) ? a.r<b.r: a.r>b.r : a.l < b.l; 这样能快是因为指针移到右边后不用再跳回左边,而跳回左边后处理下一个块又要跳回右边,这样能减少一半操作,理论上能快一倍 思路 好久的题目了,之前其实只会点不修改莫队 对带修改的不大会,也就做过这一个题目 今天重新做了一边,算是有了新

cogs 1901. [国家集训队2011]数颜色

Cogs 1901. [国家集训队2011]数颜色 ★★★   输入文件:nt2011_color.in   输出文件:nt2011_color.out   简单对比时间限制:0.6 s   内存限制:512 MB [试题来源] 2011中国国家集训队命题答辩 [问题描述] 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令:1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔.2. R P Col 把第P支画笔替换为

[国家集训队2010]小Z的袜子

★★★   输入文件:hose.in   输出文件:hose.out   简单对比 时间限制:1 s   内存限制:512 MB [题目描述] 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬. 你的任务便

BZOJ 2038: [2009国家集训队]小Z的袜子(hose)

2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7676  Solved: 3509[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只

BZOJ 2038: [2009国家集训队]小Z的袜子(hose) ( 莫队 )

莫队..先按sqrt(n)分块, 然后按块的顺序对询问排序, 同块就按右端点排序. 然后就按排序后的顺序暴力求解即可. 时间复杂度O(n1.5) ------------------------------------------------------------------------------ #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 50009; int N,

洛谷 1775. [国家集训队2010]小Z的袜子

1775. [国家集训队2010]小Z的袜子 ★★★   输入文件:hose.in   输出文件:hose.out   简单对比时间限制:1 s   内存限制:512 MB [题目描述] 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,