求区间颜色,还加上少量的修改。
具体看代码注释。
#include <bits/stdc++.h>
#define mem(x,v) memset(x,v,sizeof(x))
#define go(i,a,b) for (int i = a; i <= b; i++)
#define og(i,a,b) for (int i = a; i >= b; i--)
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 1e6+10;
int ans[N],m,n,Ans,now[N],t,l = 1,r,tim,s[N],Be[N],unit,T;
//ans 答案数组,Ans 每个区间答案, now 记录修改之后当前点的颜色。s[] 初始时的颜色。 Be 分块。
// t 表示查询区间, tim 表示时间戳,修改了多少次,
int col[N];
struct Insert{
int l,r,ID,Tim; //左右区间,位置,这个询问在多少个修改之后。
}f[N];
struct Change{
int pos,x,y; //位置,新颜色,旧颜色。
}g[N];
bool cmp(Insert a, Insert 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;
} //多关键字排序,先 l 后 r 最后 tim
void action(int x,int d){col[x] += d; if (d > 0) Ans += col[x] == 1; if (d < 0) Ans -= col[x] == 0;} //修改区间答案。
void Updata(int x, int d){if(l <= x && x <= r) action(d,1),action(s[x],-1); s[x] = d;} //改到正常的时间戳,修改节点颜色。
int main(){
scanf("%d%d",&n,&m);
unit = pow(n,0.666666);
go(i,1,n) scanf("%d",&s[i]),Be[i] = i / unit + 1, now[i] = s[i];
go(i,1,m){
char ch; int x,y;
scanf(" %c%d%d",&ch,&x,&y);
if (ch == 'Q') f[++t] = (Insert){x,y,t,tim}; else
g[++tim] = (Change){x,y,now[x]},now[x] = y;
}
sort(f+1, f + t+ 1,cmp); go(i,1,t){
while(T < f[i].Tim) Updata(g[T+1].pos,g[T+1].x),T++; //找到属于该区间的时间戳。改区间颜色。
while(T > f[i].Tim) Updata(g[T].pos,g[T].y),T--;
while(l < f[i].l) action(s[l],-1),l++; //正常莫队,
while(l > f[i].l) action(s[l-1],1),l--;
while(r < f[i].r) action(s[r+1],1),r++;
while(r > f[i].r) action(s[r],-1),r--;
ans[f[i].ID] = Ans;
}
go(i,1,t) printf("%d\n",ans[i]);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int n,m,block,blo[N],s[N],col[N*100],now[N];
int Ans[N],l,r,cntq,cntc,t,ans;
struct Query{
int l,r,tim,id;
}q[N];
struct Change{
int pos,New,Old;
}c[N];
bool cmp(Query A, Query B){
if (blo[A.l] != blo[B.l]) return A.l < B.l;
if (blo[A.r] != blo[B.r]) return A.r < B.r;
return A.tim < B.tim;
}
void act(int x, int y){
col[x] += y;
if (y > 0) ans += (col[x] == 1); //ans 记录当前区间的答案.
if (y < 0) ans -= (col[x] == 0);
}
void going(int x, int d){
if (x <= r && x >= l) act(d,1),act(s[x],-1); //如果在在正确的区间,需要修改答案.
s[x] = d; //直接复制为 d.
}
int main(){
char ss[10];
int x,y;
scanf("%d%d",&n,&m); block = pow(n,0.66666);
for (int i = 1; i <= n; ++i){
scanf("%d",&s[i]); now[i] = s[i]; blo[i] = (i - 1) / block + 1;
}
for (int i = 1; i <= m; ++i){
scanf("%s%d%d",ss,&x,&y);
if (ss[0] == 'Q') {
q[++cntq] = (Query){x,y,cntc,cntq}; //把询问的放在一起,结构体里面放 id,还有修改了多少次
} else {
c[++cntc] = (Change){x,y,now[x]}; now[x] = y; //把修改的放在一起,记录修改 了多少次.
}
}
sort(q+1,q+cntq+1,cmp); //把询问排序,关键字 l, r ,tim.
l = 1; r = 0; t = 0;
for (int i = 1; i<= cntq; ++i){
while(t < q[i].tim) going(c[t+1].pos, c[t+1].New),t++; //首先时间回溯.找到正确的修改时间.
while(t > q[i].tim) going(c[t].pos, c[t].Old), t--;
while(l < q[i].l) act(s[l], -1),l++;
while(l > q[i].l) act(s[l-1],1), l--;
while(r < q[i].r) act(s[r+1],1),r++;
while(r > q[i].r) act(s[r],-1), r--;
Ans[q[i].id] = ans;
}
for (int i = 1; i <= cntq; ++i)
printf("%d\n",Ans[i]);
return 0;
}