loj #6282. 数列分块入门 6 #6282. 数列分块入门 6
题目描述
给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及单点插入,单点询问,数据随机生成。
输入格式
第一行输入一个数字 nnn。
第二行输入 nnn 个数字,第 i 个数字为 aia_iai,以空格隔开。
接下来输入 nnn 行询问,每行输入四个数字 optmathrm{opt}opt、lll、rrr、ccc,以空格隔开。
若 opt=0mathrm{opt} = 0opt=0,表示在第 lll 个数字前插入数字 rrr (ccc 忽略)。
若 opt=1mathrm{opt} = 1opt=1,表示询问 ara_rar 的值(lll 和 ccc 忽略)。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
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\%100% 的数据,1≤n≤100000,−231≤others 1 leq n leq 100000, -2^{31} leq mathrm{others}1≤n≤100000,−231≤others、ans≤231−1 mathrm{ans} leq 2^{31}-1ans≤231−1。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define maxn 2010 using namespace std; int n,block,p,T,a[maxn][maxn],b[maxn][maxn],len[maxn]; void reset(){ int y=0,k=p/block,ll=0; if(p%block!=0)k++; p+=block;block=sqrt(p); T=0; for(int i=1;i<=k;i++) for(int j=1;j<=len[i];j++){ y++; int kk=(y-1)/block+1; b[kk][++ll]=a[i][j]; a[i][j]=0; if(ll==block)ll=0; } k=p/block; if(p%block!=0)k++; for(int i=1;i<=k;i++){ if(i!=k||p%block==0)len[i]=block; else len[i]=p-block*block; for(int j=1;j<=len[i];j++)a[i][j]=b[i][j]; } } int main(){ scanf("%d",&n);p=n;block=sqrt(n); for(int i=1;i<=n;i++){ int k=(i-1)/block+1; int x;scanf("%d",&x); a[k][++len[k]]=x; } T=0; for(int i=1;i<=n;i++){ int op,l,r,c; scanf("%d%d%d%d",&op,&l,&r,&c); if(op==0){ int k=0,t; for(t=1;t<=block;t++){ if(k+len[t]>=l)break; k+=len[t]; } len[t]++; for(int j=len[t];j>=l-k+1;j--) a[t][j]=a[t][j-1]; a[t][l-k]=r; T++; if(T==block)reset(); } else { int k=0,t; for(t=1;t<=block;t++){ if(k+len[t]>=r)break; k+=len[t]; } printf("%d ",a[t][r-k]); } } return 0; }