题目大意:给定一个长度为 N 的序列,每个点有一个颜色。现给出 M 个操作,支持单点修改颜色和询问区间颜色数两个操作。

题解:学会了序列带修改的莫队。

莫队本身是不支持修改的。带修该莫队的本质也是对询问进行分块,不过在莫队转移时需要多维护一个时间维度,即:每个操作的相对顺序。具体来讲,将序列分成 \(O(n^{1 \over 3})\) 块,每个块的大小是 \(O(n^{2 \over 3})\),对询问的排序的优先级顺序是:询问左端点所在块,询问右端点所在块,询问的时间顺序。经过分析,带修该莫队的时间复杂度为 \(O(n^{5 \over 3})\),具体分析方式和静态莫队类似。对排好序的询问进行按顺序处理,首先考虑时间维度,通过比较时间的先后,决定是顺序执行还是时间倒流,这可以通过记录一个 pre 变量来维护。

注意:在莫队中,对于 l 的初始化应该为 1,r 的初始化应该为 0,这是由询问转移的性质决定的。对于带修改莫队来说,时间维度也需要维护一个变量,表示当前的时间。时间的初始化应该为 0。

代码如下

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define cls(a,b) memset(a,b,sizeof(a))
#define debug(x) printf("x = %d\n",x)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=5e4+10;
const int maxm=1e6+10;
const double eps=1e-6;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
ll x=0,f=1;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
return f*x;
}
/*--------------------------------------------------------*/ char s[4];
int n,m,l=1,r=0,cur=0,a[maxn],cnt[maxm],sum,ans[maxn];
struct query{int id,l,r,t,bl,br;}q[maxn];
struct node{int pos,val,pre,t;}mo[maxn];
int tot,tot1,tot2;
inline int get(int pos){return (pos-1)/tot+1;}
bool cmp(const query &x,const query &y){
return x.bl!=y.bl?x.bl<y.bl:x.br!=y.br?x.br<y.br:x.t<y.t;
} void read_and_parse(){
n=read(),m=read(),tot=pow(n,0.6);
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=m;i++){
scanf("%s",s);
if(s[0]=='Q')++tot1,q[tot1].id=tot1,q[tot1].t=i,q[tot1].l=read(),q[tot1].r=read(),q[tot1].bl=get(q[tot1].l),q[tot1].br=get(q[tot1].r);
else ++tot2,mo[tot2].t=i,mo[tot2].pos=read(),mo[tot2].val=read();
}
sort(q+1,q+tot1+1,cmp);
} inline void update(int x,int f){
if(f==1){
if(!cnt[a[x]])++sum;
++cnt[a[x]];
}else{
--cnt[a[x]];
if(!cnt[a[x]])--sum;
}
}
void update2(int x,int f){
if(mo[x].pos>=l&&mo[x].pos<=r){
--cnt[a[mo[x].pos]];
if(!cnt[a[mo[x].pos]])--sum;
}
if(f==1)mo[x].pre=a[mo[x].pos],a[mo[x].pos]=mo[x].val;
else a[mo[x].pos]=mo[x].pre;
if(mo[x].pos>=l&&mo[x].pos<=r){
if(!cnt[a[mo[x].pos]])++sum;
++cnt[a[mo[x].pos]];
}
}
void change(int now){
while(cur<tot2&&mo[cur+1].t<=now)update2(++cur,1);
while(cur&&mo[cur].t>now)update2(cur--,-1);
} void solve(){
for(int i=1;i<=tot1;i++){
change(q[i].t);
while(r<q[i].r)update(++r,1);
while(r>q[i].r)update(r--,-1);
while(l>q[i].l)update(--l,1);
while(l<q[i].l)update(l++,-1);
ans[q[i].id]=sum;
}
for(int i=1;i<=tot1;i++)printf("%d\n",ans[i]);
} int main(){
read_and_parse();
solve();
return 0;
}

【洛谷P1903】数颜色的更多相关文章

  1. Bzoj2120/洛谷P1903 数颜色(莫队)

    题面 Bzoj 洛谷 题解 考虑对操作离线后分块处理询问操作(莫队算法),将询问操作按照编号分块后左端点第一关键字,右端点第二关键字排序(分块大小为\(n^{\frac 23}\)),对于每一个询问操 ...

  2. [bzoj2120] [洛谷P1903] 数颜色

    Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜 ...

  3. 洛谷P1903 数颜色 [国家集训队] 莫队

    正解:带修莫队 解题报告: 可以理解为引入时间参数,然后就是有了仨参数,关于这个修改同样的是,如果时间是相同的,不用搞,如果时间不相同做一下时光倒流/时光推移就成嘛 但是肯定既然这样的话,按照原来的s ...

  4. 2018.07.07 洛谷 P3939 数颜色(主席树)

    P3939 数颜色 题目背景 大样例下发链接:http://pan.baidu.com/s/1c0LbQ2 密码:jigg 题目描述 小 C 的兔子不是雪白的,而是五彩缤纷的.每只兔子都有一种颜色,不 ...

  5. 洛谷——P3939 数颜色(暴力vecotr+二分)

    P3939 数颜色 $vecotr$里二分就是好用,全是$STL$ 颜色数目比较少,可以对每一种颜色弄一个$vector$记录一下,查找$l,r$内颜色数为$x$的兔子数,直接在$G[x]$这个$ve ...

  6. 洛谷P3939 数颜色 二分查找

    正解:二分 解题报告: 传送门! 话说其实我开始看到这题想到的是分块,,, 但是显然不用这么复杂,,,因为仔细看下这题,会发现每次只改变相邻的兔子的位置 所以开个vector(或者开个数组也成QwQ( ...

  7. 洛谷P3939 数颜色(二分 vector)

    题意 题目链接 Sol 直接拿vector维护每种颜色的出现位置,然后二分一下. #include<bits/stdc++.h> using namespace std; const in ...

  8. [洛谷P3939]数颜色

    题目大意:有n个物品,每个物品有一个颜色.现在有两种操作:1.查询l-r内有多少颜色为c的物品并输出.2.将第x个物品和第x+1个交换.现在让你实现这些操作. 解题思路:首先一共有300000种颜色, ...

  9. [洛谷P3939]:数颜色(二分)

    题目传送门 题目描述 小$C$的兔子不是雪白的,而是五彩缤纷的.每只兔子都有一种颜色,不同的兔子可能有相同的颜色.小$C$把她标号从$1$到$n$的$n$只兔子排成长长的一排,来给他们喂胡萝卜吃.排列 ...

  10. BZOJ2120/洛谷P1903 [国家集训队] 数颜色 [带修改莫队]

    BZOJ传送门:洛谷传送门 数颜色 题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R ...

随机推荐

  1. Web移动端---iPhone X适配(底部栏黑横线)

    一.相信大家有被iPhone X底部黑色横线支配的恐惧 上面我们可以看到,底部的导航栏被一条黑色横线所盖住,那么就很烦.下面我们可以开始进行适配环节 1.首先我们可以用 JS 判断手机环境是不是 iP ...

  2. 微信小程序自定义组件

    要做自定义组件,我们先定一个小目标,比如说我们在小程序中实现一下 WEUI 中的弹窗组件,基本效果图如下. Step1 我们初始化一个小程序(本示例基础版本库为 1.7 ),删掉里面的示例代码,并新建 ...

  3. spring boot session error

    Error starting ApplicationContext. To display the conditions report re-run your application with 'de ...

  4. 解析$(this).data('type');

    html: <button type="button" class="layui-btn layui-btn-sm" data-type="ad ...

  5. do not track

    privacy.trackingprotection.enabled

  6. Nginx 网络事件

    L27-29 应用层(如浏览器等一系列组成的发送get请求) 传输层 系统内核打开一个端口将客户端IP及端口和服务端IP及端口记录下来一并传输到网络层 网络层 打包后到链路层 再到客户端路由器至广域网

  7. chrome实用快捷键速记

    标签页和窗口快捷键 操作 快捷键 打开新窗口 Ctrl + n 无痕模式下打开新窗口 Ctrl + Shift + n 打开新的标签页,并跳转到该标签页 Ctrl + t 重新打开最后关闭的标签页,并 ...

  8. nginx压测工具--wrk

    基本使用 命令行敲下wrk,可以看到使用帮助 Usage: wrk <options> <url> Options: -c, --connections <N> C ...

  9. 洛谷3823 [NOI2017] 蚯蚓排队 【哈希】

    题目分析: 从$\sum|S|$入手.共考虑$\sum|S|$个$f(t)$.所以我们要一个对于每个$f(t)$在$O(1)$求解的算法.不难想到是哈希. 然后考虑分裂和合并操作.一次合并操作要考虑合 ...

  10. 学习Android过程中遇到的未解决问题(个人笔记,细节补充,随时更新)

    201811/13 使用HttpURLConnection对象调用方法又出现IO异常,我又百度个博客搜寻答案,未果.下午试试真机,完美.自己建了服务器tomcat,编写android访问自己tomca ...