整体二分的复杂度

这里先写如何证明普通整体二分的复杂度是 \(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;
}
posted @ 2024-02-22 20:20  fzrcy  阅读(72)  评论(0)    收藏  举报