[BZOJ2120]数颜色

本文介绍了一种基于莫队算法的改进版本——带修莫队算法,该算法用于处理区间查询与修改的问题。通过将数据序列划分为若干块,并采用特定的排序策略来优化查询效率,特别适用于离线处理大量区间查询与修改操作的场景。

题目大意:
  给你一个长度为$n$的正整数序列$A(A_i\leq10^6)$。
  给出$m$次操作,操作包含以下两种:
    1.将$A_p$上的数修改为$c$;
    2.询问区间$[l,r]$中不同数的个数。
思路:
  带修莫队。
  对于询问区间下标,每$n^\frac{2}{3}$个为一块,共分为$n^\frac{1}{3}$块。
  首先对于询问下标按块排序,对于左右端点所属块对应相同的,按时间先后排序。
  离线处理询问时,区间的转移就是普通莫队的转移。时间的转移暴力修改。

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cctype>
 4 #include<algorithm>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 inline char getalpha() {
13     register char ch;
14     while(!isalpha(ch=getchar()));
15     return ch;
16 }
17 const int N=10001,MAX=1000001;
18 int tot,a[N],b[N],bel[N],ans[N],cnt[MAX],tmp;
19 struct Query {
20     int l,r,t,id;
21     bool operator < (const Query &another) const {
22         if(bel[l]==bel[another.l]) {
23             if(bel[r]==bel[another.r]) {
24                 return t<another.t;
25             }
26             return bel[r]<bel[another.r];
27         }
28         return bel[l]<bel[another.l];
29     }
30 };
31 Query q[N];
32 struct Modify {
33     int p,c,last;
34 };
35 Modify mo[N];
36 inline void ins(const int &x) {
37     if(!cnt[a[x]]++) tmp++;
38 }
39 inline void del(const int &x) {
40     if(!--cnt[a[x]]) tmp--;
41 }
42 int main() {
43     const int n=getint(),m=getint(),block=pow(n,2./3);
44     for(register int i=1;i<=n;i++) {
45         a[i]=b[i]=getint();
46         bel[i]=i/block;
47     }
48     for(register int i=0;i<m;i++) {
49         const char opt=getalpha();
50         if(opt=='Q') {
51             const int l=getint(),r=getint();
52             q[i-tot]=(Query){l,r,tot,i-tot};
53         }
54         if(opt=='R') {
55             const int p=getint(),c=getint();
56             mo[++tot]=(Modify){p,c,b[p]};
57             b[p]=c;
58         }
59     }
60     std::sort(&q[0],&q[m-tot]);
61     for(register int i=0,l=1,r=0,t=0;i<m-tot;i++) {
62         while(r<q[i].r) ins(++r);
63         while(l>q[i].l) ins(--l);
64         while(r>q[i].r) del(r--);
65         while(l<q[i].l) del(l++);
66         while(t<q[i].t) {
67             t++;
68             if(l<=mo[t].p&&mo[t].p<=r) {
69                 del(mo[t].p);
70                 a[mo[t].p]=mo[t].c;
71                 ins(mo[t].p);
72             } else {
73                 a[mo[t].p]=mo[t].c;
74             }
75         }
76         while(t>q[i].t) {
77             if(l<=mo[t].p&&mo[t].p<=r) {
78                 del(mo[t].p);
79                 a[mo[t].p]=mo[t].last;
80                 ins(mo[t].p);
81             } else {
82                 a[mo[t].p]=mo[t].last;
83             }
84             t--;
85         }
86         ans[q[i].id]=tmp;
87     }
88     for(register int i=0;i<m-tot;i++) {
89         printf("%d\n",ans[i]);
90     }
91     return 0;
92 }

 

转载于:https://www.cnblogs.com/skylee03/p/8427124.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值