CF418E Tricky Password(未完待續)
阿新 • • 發佈:2020-07-28
https://www.luogu.com.cn/problem/CF418E
分塊
找規律,可以發現每兩行(除第一行外)形成一個迴圈
所以我們只要求解前三行資料就可以了
\[定義:\\ 第一行為:a_{1},a_{2},\cdots ,a_{m}\\ 第二行為:b_{1},b_{2},\cdots ,b_{m}\\ 第三行為:c_{1},c_{2},\cdots ,c_{m}\\ f_{i,j}表示前i塊中j在a中出現了幾次\\ g_{i,j}表示前i塊中j在b中出現了幾次\\ 修改操作暴力更新每個塊即可 \]
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #define N 200005 using namespace std; int xx,yy,B; int n,m,k,km,cc,lar,a[N],d[N],l[N],r[N],bel[N]; int x,y,opt,w; int f[105][200005],g[105][200005]; struct Ques { int opt,x,y; }q[N]; inline int read() { int s=0; char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) { s=s*10+c-'0'; c=getchar(); } return s; } int main() { m=read(); for (int i=1;i<=m;i++) a[i]=read(),d[i]=a[i]; k=read(); km=m; for (int i=1;i<=k;i++) { q[i].opt=read(),q[i].x=read(),q[i].y=read(); if (q[i].opt==1) { swap(q[i].x,q[i].y); d[++km]=q[i].y; } } sort(d+1,d+km+1); cc=unique(d+1,d+km+1)-d-1; for (int i=1;i<=m;i++) a[i]=lower_bound(d+1,d+cc+1,a[i])-d; for (int i=1;i<=k;i++) if (q[i].opt==1) q[i].y=lower_bound(d+1,d+cc+1,q[i].y)-d; B=(int)sqrt(m)+1; if (m/B+1>100) B=1000; for (int i=1;i<=m;i++) { bel[i]=i/B+1; if (!l[bel[i]]) l[bel[i]]=i; r[bel[i]]=i; } for (int i=1;i<=bel[m];i++) { lar=0; for (int j=0;j<=cc;j++) f[i][j]=f[i-1][j],lar=max(lar,f[i-1][j]); for (int j=0;j<=lar;j++) g[i][j]=g[i-1][j]; for (int j=l[i];j<=r[i];j++) { f[i][a[j]]++; g[i][f[i][a[j]]]++; } } for (int i=1;i<=k;i++) { x=q[i].x,y=q[i].y,opt=q[i].opt; if (opt==2) { if (x==1) printf("%d\n",d[a[y]]); else if (x%2==0) { w=bel[y]-1; for (int j=l[w+1];j<=y;j++) f[w][a[j]]++; printf("%d\n",f[w][a[y]]); for (int j=l[w+1];j<=y;j++) f[w][a[j]]--; } else { w=bel[y]-1; for (int j=l[w+1];j<=y;j++) f[w][a[j]]++,g[w][f[w][a[j]]]++; printf("%d\n",g[w][f[w][a[y]]]); for (int j=l[w+1];j<=y;j++) g[w][f[w][a[j]]]--,f[w][a[j]]--; } } else { w=bel[x]; for (int j=w;j<=bel[m];j++) { g[j][f[j][a[x]]]--; f[j][a[x]]--; } a[x]=y; for (int j=w;j<=bel[m];j++) { f[j][a[x]]++; g[j][f[j][a[x]]]++; } } } return 0; }