码迷,mamicode.com
首页 > 其他好文 > 详细

#6282. 数列分块入门 6

时间:2019-01-27 21:56:53      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:font   make   cout   turn   pair   others   并且   math   代码   

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

题目描述

给出一个长为 nn 的数列,以及 nn 个操作,操作涉及单点插入,单点询问,数据随机生成。

输入格式

第一行输入一个数字 nn。

第二行输入 nn 个数字,第 ii 个数字为 a_iai?,以空格隔开。

接下来输入 nn 行询问,每行输入四个数字 \mathrm{opt}opt、ll、rr、cc,以空格隔开。

若 \mathrm{opt} = 0opt=0,表示在第 ll 个数字前插入数字 rr(cc 忽略)。

若 \mathrm{opt} = 1opt=1,表示询问 a_rar? 的值(ll 和 cc 忽略)。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例

样例输入

4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4

样例输出

2
3

数据范围与提示

对于 100\%100% 的数据,1 \leq n \leq 100000, -2^{31} \leq \mathrm{others}1n100000,?231others、\mathrm{ans} \leq 2^{31}-1ans231?1。

 

思路:这题主要 要解决的问题是插入数据的问题,可以想到,当插入数据的时候,对应块的大小就改变了,那么我们怎么找第r个位置的数呢?  很简单,可以暴力从第一个块开始找,一直减去每个块的

大小,知道r<块的大小时,说明r位于这个块,并且在块中的位置就是先在的r,  本题使用vector来做,动态数组,因为插入多少个数据是不知道的,应用动态数组是必然,正好vector中也有Insert(it,c)函数

在it位置插入数据c   其他的元素后移,这就很方便了。 下面是一种超时的代码:

#include<iostream>
#include<vector>
#include<math.h>
using namespace std;
const int maxn=100000+5;
int a[maxn];
vector<int> v[maxn];
int block;
pair<int,int> Query(int x)
{
    int cnt=1;
    while(x>v[cnt].size())
    {
        x-=v[cnt].size();
        cnt++;
    }
    return make_pair(cnt,x-1);//哪个块里面的第几个元素
}
void Updata(int l,int r)
{
    pair<int,int> t=Query(l);
    v[t.first].insert(v[t.first].begin()+t.second,r);//找到相应的块 并在对应位置插入r
    //重构
}
int main()
{
    int n;
    int opt,l,r,c;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    block=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        v[(i-1)/block+1].push_back(a[i]);
    }
    for(int i=1;i<=n;i++)
    {
        cin>>opt>>l>>r>>c;
        if(opt==0) Updata(l,r);
        else
        {
            pair<int,int>t=Query(r);
            cout<<v[t.first][t.second]<<endl;
        }
    }
}

 

 

为什么会超时呢?   当我们插入数据一直在一个块的时候,就会导致某个块的大小很大很大,这就使得访问的时候时间复杂度变的很大了,所以下面增加另外一个操作,重构!

有两种分块的方法  :  当根号n  次插入时  重新分块 这样时间复杂度最多也就根号n    *   n     也可以当某个块的大小很大时分块  只要能保证足够就行了

下面看代码:

#include<iostream>
#include<vector>
#include<math.h>
using namespace std;
const int maxn=100000+5;
int a[maxn];
vector<int> v[maxn];
int st[2*maxn];
int block;
int m;
int top;
int sum=0;
pair<int,int> Query(int x)
{
    int cnt=1;
    while(x>v[cnt].size())
    {
        x-=v[cnt].size();
        cnt++;
    }
    return make_pair(cnt,x-1);//哪个块里面的第几个元素
}
void Rebuild()
{
    sum=0;
    top=0;
    for(int i=1;i<=m;i++)
    {
        for(vector<int>::iterator it=v[i].begin();it!=v[i].end();it++)
        {
            st[++top]=*it;
        }
        v[i].clear();
    }
    int block2=sqrt(top);
    for(int i=1;i<=top;i++)
    {
        v[(i-1)/block2+1].push_back(st[i]);
    }
    m=(top-1)/block2+1;
}
void Updata(int l,int r)
{
    sum++;
    pair<int,int> t=Query(l);
    v[t.first].insert(v[t.first].begin()+t.second,r);//找到相应的块 并在对应位置插入r
    //重构
    if(sum==block)
        Rebuild();
}
int main()
{
    int n;
    int opt,l,r,c;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    block=sqrt(n);
    m=(n-1)/block+1;
    for(int i=1;i<=n;i++)
    {
        v[(i-1)/block+1].push_back(a[i]);
    }
    for(int i=1;i<=n;i++)
    {
        cin>>opt>>l>>r>>c;
        if(opt==0) Updata(l,r);
        else
        {
            pair<int,int>t=Query(r);
            cout<<v[t.first][t.second]<<endl;
        }
    }
}

 

#6282. 数列分块入门 6

标签:font   make   cout   turn   pair   others   并且   math   代码   

原文地址:https://www.cnblogs.com/caijiaming/p/10327363.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!