zoukankan      html  css  js  c++  java
  • 【学习笔记】快乐分块

    快乐分块

    题外话

    为什么分块算在树专题里(

    引入


    ——luogu P1975 [国家集训队]排队

    首先肯定是要统计出原来有多少个逆序对的

    然后考虑如何统计交换后的答案改变

    老师!我会暴力统计!

    你退役罢(无慈悲

    我直接给出结论(其实是我不会证明)

    设交换的位置分别为(u,v),操作前逆序对个数为(ans)

    容易得到:

    对于(i in (u,v))

    (h_i < h_v)(h_i > h_u),则ans++

    (h_i > h_v)(h_i < h_u),则ans--

    然后问题转化为统计((u,v))中有多少个数满足以上四种条件,就可以愉快树套树了

    时间复杂度(O(nlog^2n))

    可我不会树套树啊(

    所以我们考虑对原数组分块

    分块是什么

    简而言之,分块是对数组进行分组,对于包含在区间内的整个组直接用较低时间复杂度的方法回答询问,剩下的则暴力统计

    其中每一个整组叫做“块”

    拿之前例题举例

    假设没有修改操作

    如果询问的((u,v))都是((1,n)),显然我们可以对整个数组进行排序,然后二分得到答案

    假设我们已经对原数组进行了分块,那么对于每个在区间((u,v))里的整块,我们都可以对其进行排序,然后二分得到答案

    对于剩下的非整块元素(一般称作边角),直接暴力统计

    假设我们每(K)个元素分成一组,那么这么一趟的最坏时间复杂度为:

    (O(K+frac{n}{K}logK))

    显然当(K=sqrt{n})时时间复杂度最优,为(O(sqrt{n}+sqrt{n}logsqrt{n}))

    感觉十分科学的时间复杂度(

    现在,还有修改

    我们原本的块是有序的

    新交换进来的数,我们直接对新来的数插入排序即可

    时间复杂度(O(K))

    考虑到询问的复杂度,仍是当(K=sqrt{n})时时间复杂度最优

    分块的优势

    当你不会写树套树时骗分

    对于树套树这种码量大又不好调的数据结构,我这种人在考场上基本不可能打出来

    相比较而说,分块会相对好些很多

    况且,对于树套树那巨大的常数,分块的小常数常常能让他跑得比复杂度更优的复杂度更快

    还有呢

    对于部分树套树难以统计的信息,分块常常能更好地统计

    深刻理解请去刷ynOI

    例题代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    
    const int N=20010;
    
    inline void read(int &x) {
        x=0;
        int f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9') {
            if (ch=='-') {
                f=-1;
            }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9') {
            x=x*10+ch-'0';
            ch=getchar();
        }
        x*=f;
    }
    
    int ans;
    int a[N];
    
    namespace merge_sort {
    int t[N];
    inline void merge_sort(int l,int r) {
        if (r<=l+1) {
            return;
        }
        int mid=(l+r)>>1;
        int p=l,q=mid,cur=l;
        merge_sort(l,mid);
        merge_sort(mid,r);
        while(p<mid||q<r) {
            if (q>=r||(p<mid&&a[p]<=a[q])) {
                t[cur++]=a[p++];
            } else {
                t[cur++]=a[q++];
                ans+=(long long)mid-p;
            }
        }
        for(int i=l;i<r;i++) {
            a[i]=t[i];
        }
    }
    }
    
    int n,m;
    int siz;
    int h[N];
    int id[N],lft[N],rgh[N];
    int k[N];
    
    inline void change_ans(int x,int y,int i) {
        if (h[i]>h[x]) {
            ans++;
        }
        if (h[i]<h[x]) {
            ans--;
        }
        if (h[i]<h[y]) {
            ans++;
        }
        if (h[i]>h[y]) {
            ans--;
        }
    }
    
    void resort(int x,int y) {
        int L=id[x],R=id[y];
        int l=lower_bound(k+lft[L],k+rgh[L]+1,h[x])-k;
        int r=lower_bound(k+lft[R],k+rgh[R]+1,h[y])-k;
        k[l]=h[y];
        int tmp=l;
        while(tmp>lft[L]&&k[tmp]<k[tmp-1]) {
            swap(k[tmp],k[tmp-1]);
            tmp--;
        }
        while(tmp<rgh[L]&&k[tmp]>k[tmp+1]) {
            swap(k[tmp],k[tmp+1]);
            tmp++;
        }
        k[r]=h[x];
        tmp=r;
        while(tmp>lft[R]&&k[tmp]<k[tmp-1]) {
            swap(k[tmp],k[tmp-1]);
            tmp--;
        }
        while(tmp<rgh[R]&&k[tmp]>k[tmp+1]) {
            swap(k[tmp],k[tmp+1]);
            tmp++;
        }
        swap(h[x],h[y]);
        /*
        printf("k:");
        for(int i=1;i<=n;i++) {
            printf("%d ",k[i]);
        }
        printf("
    h:");
        for(int i=1;i<=n;i++) {
            printf("%d ",h[i]);
        }
        */
    }
    
    int main() {
        read(n);
        siz=sqrt(n);
        for(int i=1;i<=n;i++) {
            read(h[i]);
            k[i]=a[i]=h[i];
            id[i]=(i-1)/siz+1;
        }
        for(int i=1;i<=n;i++) {
            if (!lft[id[i]]) {
                lft[id[i]]=i;
            }
            int j=n-i+1;
            if (!rgh[id[j]]) {
                rgh[id[j]]=j;
            }
        }
        for(int i=1;i<=id[n];i++) {
            sort(k+lft[i],k+rgh[i]+1);
        }
        merge_sort::merge_sort(1,n+1);
        printf("%d
    ",ans);
        read(m);
        for(int i=1;i<=m;i++) {
            int x,y;
            read(x),read(y);
            if (x>y) {
                swap(x,y);
            }
            if (h[x]==h[y]) {
                printf("%d
    ",ans);
                continue;
            }
            if (h[x]<h[y]) {
                ans++;
            } else {
                ans--;
            }
            if (id[x]==id[y]) {
                for(int i=x+1;i<y;i++) {
                    change_ans(x,y,i);
                }
                printf("%d
    ",ans);
                resort(x,y);
                continue;
            }
            for(int i=x+1;i<=rgh[id[x]];i++) {
                change_ans(x,y,i);
            }
            for(int i=lft[id[y]];i<y;i++) {
                change_ans(x,y,i);
            }
            //统计以下:
            //有多少个数小于h[x]:-
            //有多少个数小于h[y]:+
            //有多少个数大于h[x]:+
            //有多少个数大于h[y]:-
            for(int i=id[x]+1;i<id[y];i++) {
                int o1,o2,o3,o4;
                o1=o2=o3=o4=0;
                if (k[lft[i]]<h[x]) {
                    o1=lower_bound(k+lft[i],k+rgh[i]+1,h[x])-k;
                    o1=o1-lft[i];
                }//h[x]-
                if (k[rgh[i]]>h[x]) {
                    o2=upper_bound(k+lft[i],k+rgh[i]+1,h[x])-k;
                    o2=rgh[i]+1-o2;
                }//h[x]+
                if (k[lft[i]]<h[y]) {
                    o3=lower_bound(k+lft[i],k+rgh[i]+1,h[y])-k;
                    o3=o3-lft[i];
                }//h[y]+
                if (k[rgh[i]]>h[y]) {
                    o4=upper_bound(k+lft[i],k+rgh[i]+1,h[y])-k;
                    o4=rgh[i]+1-o4;
                }//h[y]-;
                //printf("o:%d %d %d %d
    ",o1,o2,o3,o4);
                ans=ans-o1+o2+o3-o4;
            }
            printf("%d
    ",ans);
            resort(x,y);
        }
        return 0;
    }
    
  • 相关阅读:
    mybatis-plus 错误 java.lang.NoClassDefFoundError
    MySQL+navicat-1064 Error解决方案
    cnblogs博客园修改网站图标icon
    python+pycharm+PyQt5 图形化界面安装教程
    vuex的安装与使用
    vue-router的安装和使用
    VUE-CLI3如何更改配置
    VUE-CL3创建项目
    VUE-CLI2的初始化项目过程
    vuecli脚手架的安装与配置
  • 原文地址:https://www.cnblogs.com/tt66ea-blog/p/12989474.html
Copyright © 2011-2022 走看看