数据结构:分块-单点插入和单点询问

典型的平衡树操作了

每一个块用动态数组维护,每次插入是找到对应的块

然后直接插,这个元素之后的数字都平移一位,如果用链表的话更好

如果块的大小不平衡了,要进行重新分块的 操作

每根号n次插入后,重新把数列平均分一下块

重构需要的复杂度为O(n),重构的次数为√n

也可以改变重构的方式,在某个块过大时重构,或者直接把这个过大的块一分为二

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<vector>
 5 using namespace std;
 6 const int maxn=100005;
 7 long long read()
 8 {
 9     long long x=0,f=1;char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
11     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
12     return x*f;
13 }
14 int n,blo,top,m;
15 int v[maxn],st[maxn];
16 vector<int> ve[1005];
17 pair<int,int> query(int b)
18 {
19     int x=1;
20     while(b>ve[x].size()) b-=ve[x].size(),x++;
21     return make_pair(x,b-1);  //返回哪个块儿的第几个 
22 }
23 void rebuild()
24 {
25     top=0;
26     for(int i=1;i<=m;i++)
27     {
28         for(vector<int>::iterator j=ve[i].begin();j!=ve[i].end();j++)
29             st[++top]=*j;
30         ve[i].clear();
31     }
32     int blo2=sqrt(top);
33     for(int i=1;i<=top;i++)
34         ve[(i-1)/blo2+1].push_back(st[i]);
35     m=(top-1)/blo2+1;
36 }
37 void insert(int a,int b)  //在a的前面插入b 
38 {
39     pair<int,int> t=query(a);
40     ve[t.first].insert(ve[t.first].begin()+t.second,b);
41     if(ve[t.first].size()>20*blo) rebuild(); 
42 }
43 int main()
44 {
45     n=read();blo=sqrt(n);
46     for(int i=1;i<=n;i++) v[i]=read();
47     for(int i=1;i<=n;i++)
48         ve[(i-1)/blo+1].push_back(v[i]);
49     m=(n-1)/blo+1;
50     for(int i=1;i<=n;i++)
51     {
52         int f=read(),a=read(),b=read(),c=read();
53         if(f==0) insert(a,b);
54         if(f==1)
55         {
56             pair<int,int> t=query(b);
57             printf("%d\n",ve[t.first][t.second]); 
58         }
59     }
60     return 0;
61 }

 

posted @ 2018-08-23 19:38  静听风吟。  阅读(394)  评论(0编辑  收藏  举报