題目
P3939 數顏色
分析
- 維護一個 b 數組,裏面存着每個點的顏色(b[].c)和位置(b[].id),然後排好序,
- 修改的話找到 X 和 X+1 再 b 中的位置,只需交換它倆的 id 即可(因爲肯定不會影響到相同顏色間的相對先後順序)。
- 查詢的話找到顏色 C 在 b 中的那段連續區間,再二分 L,R 能在其中包含多少即可。
- 有些小細節可以看看註釋。
程序
#include <cstdio>
#include <algorithm>
#define N 400005
using namespace std;
struct zzk{int c,id;} b[N];
bool cmp(zzk x,zzk y){
if (x.c==y.c) return x.id<y.id;
return x.c<y.c;
}
int n,m,a[N];
int ef_c(int c){
if (!c) return 0;
int l,r,mid,ret=0;
for (l=1,r=n; l<=r; ){
mid=l+r>>1;
if (b[mid].c<=c && b[mid-1].c<=c){ret=mid,l=mid+1; continue;}
r=mid-1;
}
return ret;
}
int ef_I(int l,int r,int I){
int mid,ret=l;
for (; l<=r; ){
mid=l+r>>1;
if (b[mid].id<=I){ret=mid,l=mid+1; continue;}
r=mid-1;
}
return ret;
}
void option_1(int L,int R,int C){
int lc,rc,st,ed;
lc=ef_c(C-1)+1,rc=ef_c(C);
st=ef_I(lc,rc,L),ed=ef_I(lc,rc,R);
if (b[st].id>=L && b[st].id<=R && b[st].c==C) st--;
printf("%d\n",ed-st);
}
void option_2(int X){
int C1=a[X],C2=a[X+1],lc,rc,kk1,kk2;
lc=ef_c(C1-1)+1,rc=ef_c(C1),kk1=ef_I(lc,rc,X);
lc=ef_c(C2-1)+1,rc=ef_c(C2),kk2=ef_I(lc,rc,X+1);
swap(b[kk1].id,b[kk2].id);
swap(a[X],a[X+1]);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++) scanf("%d",&a[i]),b[i].id=i,b[i].c=a[i];
sort(b+1,b+n+1,cmp);
for (int k1,k2,k3,k; m--; ){
scanf("%d",&k);
if (k==1 && scanf("%d%d%d",&k1,&k2,&k3)){
option_1(k1,k2,k3);
}
if (k==2 && scanf("%d",&k1)){
if (a[k1]==a[k1+1]) continue;
option_2(k1);
}
}
}
提示
- 當然此題還有許多數據結構做法,比如可持久化線段樹什麼的,也可以練練手。