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;
    }
    
  • 相关阅读:
    Civil 3D 二次开发 创建Civil 3D 对象—— 01 —— 创建几何空间点
    Civil 3D 二次开发 创建Civil 3D 对象—— 00 ——
    Civil 3D 二次开发 创建AutoCAD对象—— 01 —— 创建直线
    Civil 3D 二次开发 新建CLR项目出现错误C2143
    Civil 3D 二次开发 创建AutoCAD对象—— 00 ——
    了解AutoCAD对象层次结构 —— 6 ——块表记录
    datepicker97使用
    使用angular 外接 templateUrl,使用ng-include
    angularJs 遮罩
    网上找的有关css兼容问题
  • 原文地址:https://www.cnblogs.com/tt66ea-blog/p/12989474.html
Copyright © 2011-2022 走看看