LOJ #6282. 数列分块入门 6
\(\color{#0066ff}{题目描述}\)
给出一个长为 n 的数列,以及 n 个操作,操作涉及单点插入,单点询问,数据随机生成。
\(\color{#0066ff}{输入格式}\)
第一行输入一个数字 n。
第二行输入 n 个数字,第 i 个数字为 \(a_i\) ,以空格隔开。
接下来输入 n 行询问,每行输入四个数字 \(\mathrm{opt}、l、r、c\),以空格隔开。
若 \(\mathrm{opt} = 0\),表示在第 l 个数字前插入数字 r (c 忽略)。
若 \(\mathrm{opt} = 1\),表示询问 \(a_r\) 的值(l 和 c 忽略)。
\(\color{#0066ff}{输出格式}\)
对于每次询问,输出一行一个数字表示答案。
\(\color{#0066ff}{输入样例}\)
4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4
\(\color{#0066ff}{输出样例}\)
2
3
\(\color{#0066ff}{数据范围与提示}\)
对于 100% 的数据, \(1 \leq n \leq 100000, -2^{31} \leq \mathrm{others},\mathrm{ans} \leq 2^{31}-1\)。
\(\color{#0066ff}{题解}\)
如果这题纯用数组,那么,查询\(O(1)\),插入\(O(n)\)
如果这题纯用链表,那么,查询\(O(n)\),插入\(O(1)\)
如果这题用块状链表(数组+链表)那就都是\(O(\sqrt{n})\)
还是分块,每个块一个数组,块与块之间用链表连接
插入时,先整块的跳找到它的块,然后暴力把本块后面的元素向后挪一个单位,然后插入元素
当本块的大小比\(2\sqrt{n}\)还大时,就要裂成两块,暴力分裂就行了
对于查询,还是整块的跳,然后返回位置就行了
#include<cstdio>
#include<queue>
#include<vector>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cmath>
#define _ 0
#define LL long long
#define Space putchar(' ')
#define Enter putchar('\n')
#define fuu(x,y,z) for(int x=(y),x##end=z;x<=x##end;x++)
#define fu(x,y,z) for(int x=(y),x##end=z;x<x##end;x++)
#define fdd(x,y,z) for(int x=(y),x##end=z;x>=x##end;x--)
#define fd(x,y,z) for(int x=(y),x##end=z;x>x##end;x--)
#define mem(x,y) memset(x,y,sizeof(x))
#ifndef olinr
inline char getc()
{
static char buf[100001],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)? EOF:*p1++;
}
#else
#define getc() getchar()
#endif
template<typename T>inline void in(T &x)
{
int f=1; char ch; x=0;
while(!isdigit(ch=getc()))(ch=='-')&&(f=-f);
while(isdigit(ch)) x=x*10+(ch^48),ch=getc();
x*=f;
}
const int inf=0x7fffffff;
int n,num;
struct K
{
int a[2100],siz;
K *nxt;
K() {mem(a,0),siz=0,nxt=NULL;}
void *operator new (size_t)
{
static K *S=NULL,*T=NULL;
return (S==T&&(T=(S=new K[1024])+1024),S++);
}
};
K *beg=new K();
inline void init()
{
in(n),num=std::sqrt(n);
K *o=beg,*t;
fuu(i,1,n)
{
if(o->siz==num) t=new K(),o->nxt=t,o=t;
in(o->a[++o->siz]);
}
}
inline void split(K *o)
{
K *t=new K();
int mid=(1+o->siz)>>1;
fuu(i,mid+1,o->siz) t->a[++t->siz]=o->a[i];
o->siz=mid;
t->nxt=o->nxt,o->nxt=t;
}
inline void add(int pos,int key)
{
K *o=beg;
int now=0;
while(now+o->siz<pos) now+=o->siz,o=o->nxt;
int p=pos-now;
fdd(i,o->siz,p+1) o->a[i+1]=o->a[i];
o->a[p+1]=key;
o->siz++;
if(o->siz>=(num<<1)) split(o);
}
inline int query(int pos)
{
K *o=beg;
int now=0;
while(now+o->siz<pos) now+=o->siz,o=o->nxt;
return o->a[pos-now];
}
int main()
{
init();
int p,l,r,c;
while(n--)
{
in(p),in(l),in(r),in(c);
if(p==0) add(l-1,r);
else printf("%d\n",query(r));
}
return ~~(0^_^0);
}
----olinr