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);
}
posted @ 2018-12-05 10:53  olinr  阅读(260)  评论(0编辑  收藏  举报