LibreOJ 6282. 数列分块入门 6

题目链接:https://loj.ac/problem/6282

参考博客:http://www.cnblogs.com/stxy-ferryman/p/8560551.html

这里如果用数组的话元素右移肯定会超时,如果用链表查询时O(n),n次询问就是O(n^2),然后刚刚又瞟了几眼别人的博客,用分块的话主要好像是有查询位置,插入元素,重构三个操作,查询就是找我们要的这个点在第几层的第几个位置(用的是vector),大概是√n的时间复杂度,因为分成了√n块;然后找到位置之后就可以插入,也是√n,因为插入时要把元素右;然后因为极端数据数据有可能只在一个块里插入元素,所以这个块里面的元素可能远远多于其他块,导致查询时候的时间复杂度变成n,所以要把所有元素重新分块,所以重构的时间复杂度是√n,我看他们都是当一个块里的元素大于10*√n,前面10这个系数应该是可以自己看清况给的,这样的话重构次数是小于√n次的,整体的时间复杂度不太会加,^_^,反正就是比n^2低好多就是了...。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque> 
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 100005
/*struct point{
    int u,w;
};
bool operator <(const point &s1,const point &s2)
{
    if(s1.w!=s2.w)
    return s1.w>s2.w;
    else
    return s1.u>s2.u;
}*/
int lump[maxn],a[maxn*2];//lump数组用不到,可以不要,a数组是等下重构时用来存所有元素的 
vector<int>ve[1010];//存每一层的元素 
int n,m,k,t,block,Max; //Max是用来存最多有多少层 
pair<int,int> query(int l)//这个函数是用来寻找第l个元素在第几层第几个,返回一个pair<int,int>类型 
{                            //它的fist表示层数,second表示第几个,vector里元素从0开始 
    int pos=1;
    while(l>ve[pos].size())
    {
        l-=ve[pos].size();
        pos++;
    }
    return make_pair(pos,l-1);
}
void rebuild()//重构操作 
{
    int top=0;
    for(int i=1;i<=Max;i++)
    {
        for(int j=0;j<ve[i].size();j++)
        {
            a[++top]=ve[i][j];//把所有元素存起来 
        }
        ve[i].clear();//记得清空 
    }
    int block1=sqrt(top);//新的块的大小 
    for(int i=1;i<=top;i++)
    {
        ve[(i-1)/block1+1].push_back(a[i]);
    }
    Max=(top-1)/block+1;
}
void insert(int l,int r)
{
    pair<int,int>w=query(l);//找到位置 
    ve[w.first].insert(ve[w.first].begin()+w.second,r);//插入元素 
    if(ve[w.first].size()>block*10)//如果块太大就重构
    rebuild();
}
int find(int l,int r)
{
    pair<int,int>w=query(r);
    return ve[w.first][w.second];
}
int main()
{
    scanf("%d",&n);
    block=sqrt(n); 
    for(int i=1;i<=n;i++)
    {
        int x; 
        scanf("%d",&x);
        lump[i]=(i-1)/block+1;
        ve[lump[i]].push_back(x);
    }
    Max=(n-1)/block+1;
    for(int j=1;j<=n;j++)
    {
        int op,l,r,c;
        scanf("%d%d%d%d",&op,&l,&r,&c);
        if(!op)
        insert(l,r);
        else
        {
            int ans=find(l,r);
            printf("%d
",ans);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/6262369sss/p/9739292.html