【BZOJ】2453: 维护队列【BZOJ】2120: 数颜色 二分+分块(暴力能A)
先说正解:把所有相同的数相成一个链在每一个区间里的种数就是不同链的链头,那么记录每个数的上个相同数所在位置,那么只要找出l到r之间前驱值在l之前的数的个数就可以了
本人打的暴力,有一个小技巧,用char代替int水题,用int里的值不同来去掉memset
#include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<cmath> #include<iostream> #define MAXN 10100 using namespace std; char ex[103][103][11003]; map<int,int>mp; int a[MAXN],pos[MAXN],t,len,n,m,sz,f[110][110],now[11100]; inline void pre(int x) { int ans=0; for(int i=(x-1)*len+1;i<=n;i++) { if(ex[x][pos[i]][a[i]]) { for(int j=pos[i];j<=t;j++) ex[x][j][a[i]]++; continue; } for(int j=pos[i];j<=t;j++) { ex[x][j][a[i]]=1; f[x][j]++; } } } inline void work1(int ohou) { int l,r; scanf("%d%d",&l,&r); int z=pos[l],y=pos[r]; int ans=0; if(pos[r]-pos[l]<=1) { for(int i=l;i<=r;i++) { if(now[a[i]]==ohou)continue; ans++; now[a[i]]=ohou; } } else { z++,y--; ans=f[z][y]; int zzh=pos[l]*len; for(int i=l;i<=zzh;i++) { if(now[a[i]]==ohou||ex[z][y][a[i]])continue; now[a[i]]=ohou; ans++; } for(int i=(pos[r]-1)*len+1;i<=r;i++) { if(now[a[i]]==ohou||ex[z][y][a[i]])continue; now[a[i]]=ohou; ans++; } } printf("%d\n",ans); } inline void work2() { int po,to; scanf("%d%d",&po,&to); if(mp[to]==0) mp[to]=++sz; to=mp[to]; int x0=a[po]; a[po]=to; int p1=pos[po]; for(int i=p1;i>0;i--) for(int j=p1;j<=t;j++) { ex[i][j][x0]--; if(ex[i][j][x0]==0)f[i][j]--; ex[i][j][to]++; if(ex[i][j][to]==1)f[i][j]++; } } int main() { scanf("%d%d",&n,&m); len=(int)sqrt(n+0.5); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(mp[a[i]]==0) mp[a[i]]=++sz; a[i]=mp[a[i]]; pos[i]=(i-1)/len+1; } t=pos[n]; for(int i=1;i<=t;i++) pre(i); while(m--) { char s[2]; scanf("%s",s); if(s[0]=='Q')work1(m); else work2(); } return 0; }
苟利国家生死以, 岂因祸福避趋之。