[国家集训队]数颜色 / 维护队列 (带修莫队模板题)
Posted 昵称很长很长真是太好了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[国家集训队]数颜色 / 维护队列 (带修莫队模板题)相关的知识,希望对你有一定的参考价值。
题意:
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:
1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。
2、 R P Col 把第P支画笔替换为颜色Col。
为了满足墨墨的要求,你知道你需要干什么了吗?
思路:
如果没有修改的话,那么就可以用莫队很轻松的做出来(或者是主席树)。
但是带了修改我们该怎么办呢,带修莫队或者(树套树)。
空间 | 时间 | |
---|---|---|
树套树 | O ( n l o g n 2 ) O(nlogn^2) O(nlogn2) | O ( n l o g n 2 ) O(nlogn^2) O(nlogn2) |
带修莫队 | O ( n ) O(n) O(n) | n 5 / 3 n^{5/3} n5/3 |
具体可以根据题目来选择。
带修莫队块的大小为pow(2/3)时,世家复杂度时最优秀的,具体的证明:戳我
与普通莫队不同的是,加了一维时间轴。
在修改时:
1.若修改的位置在当前区间内,需要更新答案(sub原颜色,add修改后的颜色)。
2.无论修改的位置是否在当前区间内,都要进行修改(以供add和sub函数在以后更新答案)。
代码:
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define endl '\\n'
//#define ll long long
//#define int long long
using namespace std;
const int maxn=2e5+10;
int a[maxn];
struct node{
int l,r,t,id;
}q[maxn];
pair<int,int> c[maxn];
int cntq,cntc;
int be[maxn],sz;
struct rule{
bool operator ()(const node & x,const node & y)const{
if(be[x.l]!=be[y.l])return x.l<y.l;
if(be[x.r]!=be[y.r])return x.r<y.r;
return x.t<y.t;
}
};
int cnt[1000010];
int sum,ans[maxn];
int l=0,r=0,t=0;
void add(int x){
if(++cnt[a[x]]==1) sum++;
}
void sub(int x){
if(--cnt[a[x]]==0) sum--;
}
void upt(int x){
if(c[x].first>=l&&c[x].first<=r){
if(--cnt[a[c[x].first]]==0) sum--;
if(++cnt[c[x].second]==1) sum++;
}
swap(c[x].second,a[c[x].first]);
}
signed main(){
int n,m;
cin>>n>>m;
sz=pow(n,2.0/3.0);
for(int i=1;i<=n;i++){
cin>>a[i];
be[i]=i/sz+1;
}
for(int i=1;i<=m;i++){
char opt;
int x,y;
cin>>opt>>x>>y;
if(opt=='Q'){
q[++cntq].l=x;
q[cntq].r=y;
q[cntq].id=cntq;
q[cntq].t=cntc;
}
else{
c[++cntc].first=x;
c[cntc].second=y;
}
}
sort(q+1,q+cntq+1,rule());
for(int i=1;i<=cntq;i++){
while(r<q[i].r) add(++r);
while(l>q[i].l) add(--l);
while(r>q[i].r) sub(r--);
while(l<q[i].l) sub(l++);
while(t<q[i].t) upt(++t);
while(t>q[i].t) upt(t--);
ans[q[i].id]=sum;
}
for(int i=1;i<=cntq;i++) cout<<ans[i]<<endl;
}
以上是关于[国家集训队]数颜色 / 维护队列 (带修莫队模板题)的主要内容,如果未能解决你的问题,请参考以下文章