zoukankan      html  css  js  c++  java
  • #6282. 数列分块入门 6

    题目链接: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}-1ans2311。

    思路:这题主要 要解决的问题是插入数据的问题,可以想到,当插入数据的时候,对应块的大小就改变了,那么我们怎么找第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;
            }
        }
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    华东交通大学2017年ACM双基程序设计大赛题解
    hdu2010(dfs+剪枝)
    欧拉函数phic以及超大数的快速幂
    想了一天的题目QAQ 毛线数列的最值
    记一下STL的一个题
    hdu1877进制转换
    hdu1002大数相加
    hdu1576逆元的一道水题
    Courses
    CodeForce-813B The Golden Age(数学+枚举)
  • 原文地址:https://www.cnblogs.com/caijiaming/p/10327363.html
Copyright © 2011-2022 走看看