整体二分的复杂度
这里先写如何证明普通整体二分的复杂度是 \(O(n\log n\log V)\) 的:
考虑如何将复杂度卡到这个上限。显然要使得每个询问的答案均匀的分布在值域 \([1,V]\) 中,也就是在每次值域分半时,操作数(询问和修改)也分半,即:
\[\begin{aligned} T(n,V)&=\\ &=2T(\frac{n}{2},\frac{V}{2})+n\log n\\ &=\sum_{i}2^i\frac{n}{2^i}\log\frac{n}{2^i}\\ &=\sum_{i}n(\log n-i)\\ &=n\log n\log V -n\frac{\log V(\log V+1)}{2} \end{aligned} \]我们将最后一项忽略就得到了整体二分的复杂度是 \(O(n\log n\log V)\)。
P3527 [POI2011] MET-Meteors
这里仍然只证明整体二分的复杂度是 \(O((m+k)\log m\log k)\)。
这里考虑建出递归树,显然树高是 \(\log k\) 的,对于每一层来说所有太空站都会被询问一次,所有陨石雨都会下一次,所以每一层的复杂度为 \(O((m+k)\log m)\),\(\log k\) 层,所以复杂度是 \(O((m+k)\log m\log k)\)。
// Fzrcy
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
constexpr int N=3e5+9;
struct opt{int l,r,a;}op[N];
int n,m,q,ans[N],qk[N];
int id[N],tk1[N],tk2[N];
vector<int>p[N];
struct BIT{
LL c[N];
inline void add(int x,int y){for(;x<=m;x+=x&-x)c[x]+=y;}
inline LL ask(int x){LL s=0;for(;x;x-=x&-x)s+=c[x];return s;}
inline void add(int x,int y,LL z){add(x,z),add(y+1,-z);}
}Tr;
inline void Apply(opt x,bool ok=0){
if(ok)x.a=-x.a;
if(x.l<=x.r) Tr.add(x.l,x.r,x.a);
else Tr.add(x.l,m,x.a),Tr.add(1,x.r,x.a);
}
inline void solve(int l,int r,int ql,int qr){
if(l>r||ql>qr)return;
if(l==r){
for(int i=ql;i<=qr;i++)ans[id[i]]=l;
return;
}
int mid=l+r>>1,c1=0,c2=0;
for(int i=l;i<=mid;i++)Apply(op[i]);
for(int i=ql;i<=qr;i++){
LL sum=0;
for(auto j:p[id[i]]){
sum+=Tr.ask(j);
if(sum>=qk[id[i]])break;
}
if(sum>=qk[id[i]])tk1[++c1]=id[i];
else tk2[++c2]=id[i],qk[id[i]]-=sum;
}
for(int i=l;i<=mid;i++)Apply(op[i],1);
memcpy(id+ql,tk1+1,c1<<2);
memcpy(id+ql+c1,tk2+1,c2<<2);
solve(l,mid,ql,qr-c2);solve(mid+1,r,ql+c1,qr);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin>>n>>m;
for(int i=1,x;i<=m;i++)
cin>>x,p[x].push_back(i);
for(int i=1;i<=n;i++)cin>>qk[i];
cin>>q;
for(int i=1;i<=q;i++)
cin>>op[i].l>>op[i].r>>op[i].a;
for(int i=1;i<=n;i++)id[i]=i;
solve(1,q+1,1,n);
for(int i=1;i<=n;i++)
if(ans[i]==q+1)cout<<"NIE\n";
else cout<<ans[i]<<'\n';
return 0;
}
P1527 [国家集训队] 矩阵乘法
这里仍然只证明复杂度为 \(O((n^2+q)\log^2\log V)\)。
递归树一共有 \(\log V\) 层,每一层有 \(n^2\) 次插入操作,\(q\) 次询问,单次操作的复杂度为 \(O(\log^2 n)\)。
// Fzrcy
#include <bits/stdc++.h>
#define RG register
#define R RG int
#define inl inline
#define gc getchar()
using namespace std;
inl int in(){
char c;R x=0,bo=0;
while(!isdigit(c=gc))if(c=='-')bo=1;
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=gc;
return bo?-x:x;
}
constexpr int N=4e5+2;
int n,m,id[N],b[N],bc;
struct Node{
int op,ID;
int x,y,v,xx,yy,Kth,ans;
}a[N];
struct Tree{
int c[502][502];
void add(R x,R y,R v){
for(R i=x;i<=n;i+=i&-i)
for(R j=y;j<=n;j+=j&-j)
c[i][j]+=v;
}
int ask(R x,R y){
R ans=0;
for(R i=x;i;i-=i&-i)
for(R j=y;j;j-=j&-j)
ans+=c[i][j];
return ans;
}
int ask(R x,R y,R xx,R yy){
return ask(xx,yy)-ask(x-1,yy)-ask(xx,y-1)+ask(x-1,y-1);
}
}tr;
int Lid[N],Rid[N];
void sol(R l,R r,R ql,R qr){
if(ql>qr||l>r)return;if(ql==qr){
for(R i=l;i<=r;i++)
if(a[id[i]].op)
a[id[i]].ans=b[ql];
return;
}
R mid=ql+qr>>1,Lc=0,Rc=0;
for(R i=l;i<=r;i++){
R x=id[i];
if(a[x].op==0){
if(a[x].v<=b[mid])
tr.add(a[x].x,a[x].y,1),Lid[++Lc]=x;
else Rid[++Rc]=x;
}
else{
R num=tr.ask(a[x].x,a[x].y,a[x].xx,a[x].yy);
if(num>=a[x].Kth)Lid[++Lc]=x;
else Rid[++Rc]=x,a[x].Kth-=num;
}
}
for(R i=l;i<=r;i++){
R x=id[i];
if(a[x].op==0&&a[x].v<=b[mid])
tr.add(a[x].x,a[x].y,-1);
}
R cur=l,tmp=0;
for(R i=1;i<=Lc;i++)id[cur++]=Lid[i];
tmp=cur-1;
for(R i=1;i<=Rc;i++)id[cur++]=Rid[i];
sol(l,tmp,ql,mid);sol(tmp+1,r,mid+1,qr);
}
int main(){
n=in(),m=in();R cur=0;
for(R i=1;i<=n*n+m;i++)id[i]=i;
for(R i=1,x;i<=n;i++)for(R j=1;j<=n;j++)
x=in(),a[++cur]={0,0,i,j,x,0,0,0,0},b[++bc]=x;
for(R i=1;i<=m;i++){
R x=in(),y=in(),xx=in(),yy=in(),Kth=in();
a[++cur]={1,i,x,y,0,xx,yy,Kth,0};
}
sort(b+1,b+bc+1);bc=unique(b+1,b+bc+1)-b-1;
sol(1,cur,1,bc);
for(R i=1;i<=cur;i++)if(a[i].op)
printf("%d\n",a[i].ans);
return 0;
}

浙公网安备 33010602011771号