#6282. 数列分块入门 6
Posted xiongtao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#6282. 数列分块入门 6相关的知识,希望对你有一定的参考价值。
题目链接:https://loj.ac/problem/6282
题目描述
给出一个长为 n 的数列,以及 n 个操作,操作涉及单点插入,单点询问,数据随机生成。
输入格式
第一行输入一个数字 n。
第二行输入 n 个数字,第 i 个数字为 ai?,以空格隔开。
接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。
若 opt=0,表示在第 l 个数字前插入数字 r (c 忽略)。
若 opt=1,表示询问 ar? 的值(l 和 c 忽略)。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4
样例输出
2
3
思路:每一个分块的数据用vector来维护,这样便于实现插入操作,并且往后挪移一位元素的复杂也不会太高。
如果插入元素太多的话,需要重新分块,因为不重新分块,可能每次都查询这个块,会超时的。
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<vector> #include<cmath> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn=1e5+10; int a[2*maxn],n,block,maxpos; vector<int>v[1010]; pair<int,int> query(int l)//查找第l个元素的位置 { int cnt=1; while(l>v[cnt].size()) { l-=v[cnt].size(); cnt++; } return make_pair(cnt,l-1); } void rebuild()//重新分块 { int cnt=0; for(int i=1;i<=maxpos;i++) { for(int j=0;j<v[i].size();j++) a[++cnt]=v[i][j]; v[i].clear(); } block=sqrt(cnt);//可要可不要,要即是用新的块大小,不要block变化不大,没有关系 for(int i=1;i<=cnt;i++) { v[(i-1)/block+1].push_back(a[i]); } maxpos=(cnt-1)/block+1; } void insert(int l,int r)//插入 { pair<int,int> w=query(l);//找到插入的位置 v[w.first].insert(v[w.first].begin()+w.second,r);//插入进去 if(v[w.first].size()>10*block)//如果插入太多,导致块变得很大,需要重新分块 rebuild(); } int find(int l,int r) { pair<int ,int >w=query(r); return v[w.first][w.second]; } int main() { scanf("%d",&n); block=sqrt(n); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); v[(i-1)/block+1].push_back(x); } maxpos=(n-1)/block+1;//最后的块 int opt,l,r,c; for(int i=0;i<n;i++) { scanf("%d%d%d%d",&opt,&l,&r,&c); if(opt==0) insert(l,r); else printf("%d ",find(l,r)); } }
以上是关于#6282. 数列分块入门 6的主要内容,如果未能解决你的问题,请参考以下文章