这题用了三种算法写:
分块+二分:O(n*sqrt(n*log(n))
函数式权值分块:O(n*sqrt(n))
带修莫队+权值分块:O(n5/3)
结果……复杂度越高的实际上跑得越快……最后这个竟然进第一页了……
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int f,C; inline void R(int &x){ C=0;f=1; for(;C<'0'||C>'9';C=getchar())if(C=='-')f=-1; for(x=0;C>='0'&&C<='9';C=getchar())(x*=10)+=(C-'0'); x*=f; } void P(int x){ if(x<10)putchar(x+'0'); else{P(x/10);putchar(x%10+'0');} } #define N 50001 #define BN 320 int n,m,c[N],a[N<<1],enc,enq,num2[N],ma[N<<1],anss[N],en,en2; struct Point{int v,p;}t[N<<1]; bool operator < (const Point &a,const Point &b){return a.v<b.v;} struct ASK{int op,l,r,k,p,t;}Q[N]; bool operator < (const ASK &a,const ASK &b) { if(num2[a.l]==num2[b.l]) { if(num2[a.r]==num2[b.r]) return a.t<b.t; return num2[a.r]<num2[b.r]; } return num2[a.l]<num2[b.l]; } struct UPT{int x,y,z;}CH[N]; int l[BN],r[BN],num[N<<1],b[N<<1],sumv[BN]; void makeblock() { int sz=sqrt(en2),sum=1; if(!sz) sz=1; for(;sum*sz<en2;sum++) { l[sum]=r[sum-1]+1; r[sum]=sz*sum; for(int i=l[sum];i<=r[sum];i++) num[i]=sum; } l[sum]=r[sum-1]+1; r[sum]=en2; for(int i=l[sum];i<=r[sum];i++) num[i]=sum; } void Insert(const int &x){b[x]++; sumv[num[x]]++;} void Delete(const int &x){b[x]--; sumv[num[x]]--;} int Rank(const int &x) { int cnt=0; for(int i=1;i<num[x];i++) cnt+=sumv[i]; for(int i=l[num[x]];i<x;i++) cnt+=b[i]; return cnt+1; } int Kth(const int &x) { int cnt=0; for(int i=1;;i++) { cnt+=sumv[i]; if(cnt>=x) { cnt-=sumv[i]; for(int j=l[i];;j++) {cnt+=b[j]; if(cnt>=x) return j;} } } } int Next(const int &x) { for(int i=x+1;i<=r[num[x]];i++) if(b[i]) return i; for(int i=num[x]+1;;i++) if(sumv[i]) for(int j=l[i];;j++) if(b[j]) return j; } int Pre(const int &x) { for(int i=x-1;i>=l[num[x]];i--) if(b[i]) return i; for(int i=num[x]-1;;i--) if(sumv[i]) for(int j=r[i];;j--) if(b[j]) return j; } void Query(const int &p) { if(Q[p].op==1) anss[Q[p].p]=Rank(Q[p].k); else if(Q[p].op==2) anss[Q[p].p]=ma[Kth(Q[p].k)]; else if(Q[p].op==4) anss[Q[p].p]=ma[Pre(Q[p].k)]; else if(Q[p].op==5) anss[Q[p].p]=ma[Next(Q[p].k)]; } int op[N]; int main() { R(n); R(m); int blo=0,sz=(int)pow((double)n,2.0/3.0); if(!sz) sz=1; for(int i=1;i<=n;++i) { R(t[i].v); t[i].p=i; if(i%sz==1||sz==1) ++blo; num2[i]=blo; } en=n; for(int i=1;i<=m;++i) { R(op[i]); if(op[i]==1||op[i]==4||op[i]==5) { ++enq; ++en; R(Q[enq].l); R(Q[enq].r); Q[enq].p=enq; Q[enq].op=op[i]; Q[enq].t=enc; R(t[en].v); t[en].p=en; } else if(op[i]==2) { ++enq; R(Q[enq].l); R(Q[enq].r); R(Q[enq].k); Q[enq].p=enq; Q[enq].op=op[i]; Q[enq].t=enc; } else { ++enc; ++en; R(CH[enc].x); R(t[en].v); t[en].p=en; } } sort(t+1,t+en+1); ma[a[t[1].p]=++en2]=t[1].v; for(int i=2;i<=en;++i) { if(t[i].v!=t[i-1].v) ++en2; ma[a[t[i].p]=en2]=t[i].v; } makeblock(); memcpy(c,a,(n+1)*sizeof(int)); en=n; enc=0; enq=0; for(int i=1;i<=m;++i) { if(op[i]==3) { ++en; ++enc; CH[enc].y=a[en]; CH[enc].z=c[CH[enc].x]; c[CH[enc].x]=a[en]; } else { ++enq; if(op[i]!=2) Q[enq].k=a[++en]; } } sort(Q+1,Q+enq+1); for(int i=1;i<=Q[1].t;++i) a[CH[i].x]=CH[i].y; for(int i=Q[1].l;i<=Q[1].r;++i) Insert(a[i]); Query(1); for(int i=2;i<=enq;++i) { if(Q[i-1].t<Q[i].t) for(int j=Q[i-1].t+1;j<=Q[i].t;++j) { if(CH[j].x>=Q[i-1].l&&CH[j].x<=Q[i-1].r) { Insert(CH[j].y); Delete(a[CH[j].x]); } a[CH[j].x]=CH[j].y; } else for(int j=Q[i-1].t;j>Q[i].t;--j) { if(CH[j].x>=Q[i-1].l&&CH[j].x<=Q[i-1].r) { Insert(CH[j].z); Delete(a[CH[j].x]); } a[CH[j].x]=CH[j].z; } if(Q[i].l<Q[i-1].l) for(int j=Q[i-1].l-1;j>=Q[i].l;--j) Insert(a[j]); else for(int j=Q[i-1].l;j<Q[i].l;++j) Delete(a[j]); if(Q[i].r<Q[i-1].r) for(int j=Q[i-1].r;j>Q[i].r;--j) Delete(a[j]); else for(int j=Q[i-1].r+1;j<=Q[i].r;++j) Insert(a[j]); Query(i); } for(int i=1;i<=enq;++i) P(anss[i]),puts(""); return 0; }