称区间$[l,r]$的"信息"为其的答案和第一个、最后一个大于$x$的位置,显然通过$[l,mid]$和$[mid+1,r]$的信息可以$o(1)$合并得到$[l,r]$的信息
考虑分块,将其按$K$的块大小分块,区间查询时求出散块每一个位置的信息(将其看作一个区间)和每一个整块的信息,之后即可$o(K+frac{n}{K})$合并得到整个块的信息
下面的问题即如何求整块的信息,对整块维护:1.排序后的结果;2.当$x$为块中每一个元素时的信息;3.[luogu6466]分散层叠算法的做法4所维护的分治结构(将$x$作为小于等于$x$的最大元素即可)
对于排序后的结果时间复杂度为$o(nlog n)-o(K)$(单点修改即插入排序),当得到排序后的结果后,该块的"信息"也可以在$o(K)$的复杂度内得到——
关于答案,只需要从小到大枚举元素,每一次即加入一个元素,通过链表支持合并即可
关于第一个和最后一个大于$x$的位置,维护排序后的序列位置的后缀最小值和最大值即可
由此即可支持单点修改,单次复杂度为$o(K)$,取$K=sqrt{n}$单次复杂度即$o(sqrt{n})$
时间复杂度为$o(nlog n)-o(sqrt{n})$
(由于该oj似乎不支持提交,与某个通过的代码拍过,正确性大概是能保证的,速度大约是其1.5倍)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300005 4 #define K 600 5 #define D 3 6 #define ll long long 7 #define L (k<<1) 8 #define R (L+1) 9 #define mid (l+r>>1) 10 struct Data{ 11 int l,r; 12 ll ans; 13 }ans[N]; 14 int n,m,k,p,x,y,z,num[21],a[N],bl[N],st[K],ed[K],id[N]; 15 int read(){ 16 int x=0; 17 char c=getchar(); 18 while ((c<'0')||(c>'9'))c=getchar(); 19 while ((c>='0')&&(c<='9')){ 20 x=x*10+(c-'0'); 21 c=getchar(); 22 } 23 return x; 24 } 25 void write(ll x,char c='