块状链表(分块)2016.10.3
来源:互联网 发布:测风速的软件 编辑:程序博客网 时间:2024/06/06 01:08
参考:http://dongxicheng.org/structure/blocklink/
苏煜《对块状链表的一点研究》
一、概述
我们常用的两种线性数据结构是数组和链表,它们各有优缺点
数组特点是元素在内存中紧挨着存储,因而优点是定位快 O(1),缺点是插入删除慢 O(n)
而链表则不同,它通过指针将不同位置的元素链接起来,因而优缺点与数组正好相反:定位慢 O(n),插入删除快 O(1)
块状链表:将数组和链表的优点结合来,各种操作的时间复杂度均为 O(sqrt(n))
二、块状链表
从整体上看,块状链表是一个链表, 而在链表的每个节点上,以数组的形式存储一组元素
所谓的“块状”链表如图所示
三、基本操作
1、定位
先定位元素所在的链表节点,然后再定位该元素在数组中的位置
从链表头开始往后扫,每个节点记录本节点合法数据的长度,最终会定位为某一个块及块内偏移
2、分裂
将某个节点分裂成两个节点
3、插入
首先定位要插入的位置,然后将所在节点分裂成两个节点,并将数据放到第一个节点的末尾
如果要插入的是一大块数据,首先要将数据切成多个block(每个block对应一个块状链表的一个节点)并将这些block链起来,然后将它们插入那两个节点之间
4、删除
首先定位删除元素的位置,然后按照数组删除元素的方法删除该数据
如果删除一大块数据,首先要定位数据块首元素和末元素所在的位置,然后分别将它们所在的节点分裂成两个节点,最后删除首元素和末元素之间的节点即可
5、及时合并小分块
四、关键点和复杂度分析
该算法的核心是确定链表长度和每个节点的数组长度,以及怎么保证这个数组长度值?
设块状链表中元素总个数为 x,链表长度为 n,每个节点中数据长度为 m,则当 m=n=sqrt(x) 时,可保证 m 和 n 同时最小,此时各种操作的时间复杂度最低
在实际应用时,需维持块状链表的每个节点大小在 [sqrt(n)/2, 2*sqrt(n)],否则,块状链表会退化
维护方法是,适当的时候,对节点进行合并与分裂(维护本身不会使复杂度增加)
五、例题
1、BZOJ 1507 [NOI2003] Editor
参考:http://blog.csdn.net/greatwjj/article/details/20468249
#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>#include <bitset>#include <ctime>using namespace std;#define REP(i, n) for (int i = 0; i < (n); ++i)typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;typedef pair<int, int> Pair;const ull mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 1500;int pos, size[maxn], List[maxn], Next[maxn];char s[2000000], c, data[maxn][maxn], cmd[20];void Init(void);int New_Node(void);void Del_Node(int t);void Find(int& p, int& b);void Split(int b, int p);void Fill_Block(int b, int n, char* str, int e);void Maintain(int b);void insert(int p, int n, char* str);void erase(int p, int n);void copy(int p, int n, char* str);int main(){#ifdef __AiR_H freopen("in.txt", "r", stdin);#endif // __AiR_H int t, cur = 0, n; Init(); scanf("%d", &t); while (t--) { scanf("%s", cmd); if (cmd[0] == 'M') { scanf("%d", &cur); } else if (cmd[0] == 'I') { scanf("%d", &n); for (int i = 0; i < n;) { c = getchar(); if (32 <= c && c <= 126) { s[i++] = c; } } s[n] = '\0'; insert(cur, n, s); } else if (cmd[0] == 'D') { scanf("%d", &n); erase(cur, n); } else if (cmd[0] == 'G') { scanf("%d", &n); copy(cur, n, s); s[n] = '\0'; printf("%s\n", s); } else if (cmd[0] == 'P') { --cur; } else { ++cur; } } return 0;}int New_Node(void){ return List[pos++];}void Del_Node(int t){ List[--pos] = t;}void Find(int& p, int& b){ for (b = 0; b != -1 && p > size[b]; b = Next[b]) { p -= size[b]; }}void Fill_Block(int b, int n, char* str, int e){ if (b == -1) { return; } Next[b] = e; size[b] = n; memcpy(data[b], str, n);}void Split(int b, int p){ if (b == -1 || p == size[b]) { return; } int t = New_Node(); Fill_Block(t, size[b]-p, data[b]+p, Next[b]); Next[b] = t; size[b] = p;}void Maintain(int b){ for (; b != -1; b = Next[b]) { for (int t = Next[b]; t != -1 && size[b]+size[t] <= maxn; t = Next[b]) { memcpy(data[b]+ size[b], data[t], size[t]); size[b] += size[t]; Next[b] = Next[t]; Del_Node(t); } }}void insert(int p, int n, char* str){ int b, t, i; Find(p, b); Split(b, p); for (i = 0; i+maxn <= n; i += maxn) { t = New_Node(); Fill_Block(t, maxn, str+i, Next[b]); Next[b] = t; b = t; } if (n-i) { t = New_Node(); Fill_Block(t, n-i, str+i, Next[b]); Next[b] = t; } Maintain(b);}void erase(int p, int n){ int b, e; Find(p, b); Split(b, p); for (e = Next[b]; e != -1 && n > size[e]; e = Next[e]) { n -= size[e]; } Split(e, n); e = Next[e]; for (int t = Next[b]; t != e; t = Next[b]) { Next[b] = Next[t]; Del_Node(t); } Maintain(b);}void copy(int p, int n, char* str){ int b, t, i; Find(p, b); i = min(n, size[b]-p); memcpy(str, data[b]+p, i); for (t = Next[b]; t != -1 && i+size[t] <= n; i += size[t], t = Next[t]) { memcpy(str+i, data[t], size[t]); } if (n-i && t != -1) { memcpy(str+i, data[t], n-i); }}void Init(void){ for (int i = 1; i < maxn; ++i) { List[i] = i; } pos = 1; Next[0] = -1; size[0] = 0;}
参考:http://blog.csdn.net/qq_18455665/article/details/50650215
#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>#include <bitset>#include <ctime>using namespace std;#define REP(i, n) for (int i = 0; i < (n); ++i)typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;typedef pair<int, int> Pair;const ull mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 2e6 + 10;const int maxblock = 9000;char s[maxn], c, cmd[20];struct block { char key[maxblock + 10]; int len; block* next; block(){key[0] = len = 0, next = NULL;} void insert(int pos, int n); void erase(int pos, int n); void print(int pos, int n); block* find(int pos, int &k); void split(block *u, block *&r, int k); void merge(block *u, block *r);};block* head;block List;int main(){#ifdef __AiR_H freopen("in.txt", "r", stdin);#endif // __AiR_H int t, cur = 0, n; head = new block(); scanf("%d", &t); while (t--) { scanf("%s", cmd); if (cmd[0] == 'M') { scanf("%d", &cur); } else if (cmd[0] == 'I') { scanf("%d", &n); for (int i = 0; i < n;) { c = getchar(); if (32 <= c && c <= 126) { s[i++] = c; } } s[n] = '\0'; List.insert(cur, n); } else if (cmd[0] == 'D') { scanf("%d", &n); List.erase(cur, n); } else if (cmd[0] == 'G') { scanf("%d", &n); List.print(cur, n); } else if (cmd[0] == 'P') { --cur; } else { ++cur; } } return 0;}block* block::find(int pos, int &k){ int Count = 0; block* t = head; while (t->next) { if (Count+t->len >= pos) { break; } Count += t->len; t = t->next; } k = pos - Count; return t;}void block::split(block *u, block *&r, int k){ r = new block(); r->next = u->next, u->next = r; strcpy(r->key, u->key+k); r->len = u->len - k, u->len = k; u->key[k] = '\0';}void block::merge(block *u, block *r){ strcat(u->key, r->key), u->len += r->len; u->next = r->next, free(r), r = NULL;}void block::insert(int pos, int n){ int k; block *u = find(pos, k), *r; if (k == u->len) { r = u->next; } else { split(u, r, k); } block *t = u; int Count = 0; while (n-Count >= maxblock) { block *now = new block(); strncpy(now->key, s+Count, maxblock); now->key[maxblock] = '\0', now->len = maxblock; now->next = t->next, t->next = now; t = now, Count += maxblock; } if (n-Count) { block *now = new block(); strcpy(now->key, s+Count); now->len = n - Count, now->next = t->next; t->next = now, t = now; } if (u != head && u->next != NULL && u->len <= (maxblock/2) && u->next->len <= (maxblock/2)) { if (t == u->next) { merge(u, u->next), t = u; } else { merge(u, u->next); } } if (t != head && t->len <= (maxblock/2) && r != NULL && r->len <= (maxblock/2)) { merge(t, r); }}void block::erase(int pos, int n){ int sk, ek; block *st = find(pos, sk), *sr; block *ed = find(pos+n, ek), *er; split(ed, er, ek), split(st, sr, sk); block *t = st->next; while (t != er) { block *t_free = t; t = t->next; free(t_free); t_free = NULL; } st->next = er; if (st->len <= (maxblock/2) && er->len <= (maxblock/2)) { merge(st, er); }}void block::print(int pos, int n){ int k, Count = 0; block *now = find(pos+1, k); --k; while (now && Count < n) { while (k < now->len && Count < n) { putchar(now->key[k]); ++Count, ++k; } now = now->next, k = 0; } putchar('\n');}
2、BZOJ 2002 [Hnoi2010] Bounce 弹飞绵羊
参考:http://hzwer.com/3505.html
http://www.bilibili.com/video/av6445624/
#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>#include <bitset>#include <ctime>using namespace std;#define REP(i, n) for (int i = 0; i < (n); ++i)typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;typedef pair<int, int> Pair;const ull mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 200000 + 10;const int maxblock = 1000;int k[maxn], belong[maxn], steps[maxn], pt[maxn], Left[maxblock], Right[maxblock];int num, block, n, m, x, y, z;inline int read(void);void build(void);int main(){#ifdef __AiR_H freopen("in.txt", "r", stdin);#endif // __AiR_H n = read(); for (int i = 1; i <= n; ++i) { k[i] = read(); } build(); for (int i = n; i > 0; --i) { if (i+k[i] > n) { steps[i] = 1; } else if (belong[i] == belong[i+k[i]]) { steps[i] = steps[i+k[i]] + 1, pt[i] = pt[i+k[i]]; } else { steps[i] = 1, pt[i] = i + k[i]; } } m = read(); while (m--) { x = read(), y = read(); ++y; if (x == 1) { int ans = 0; while (1) { ans += steps[y]; if (pt[y] == 0) { break; } y = pt[y]; } printf("%d\n", ans); } else { z = read(); k[y] = z; for (int i = y; i >= Left[belong[y]]; --i) { if (belong[i] == belong[i+k[i]]) { steps[i] = steps[i+k[i]] + 1, pt[i] = pt[i+k[i]]; } else { steps[i] = 1, pt[i] = i + k[i]; } } } } return 0;}void build(void){ block = sqrt(n); num = n / block; if (n%block) { ++num; } for (int i = 1; i <= num; ++i) { Left[i] = (i-1) * block + 1; Right[i] = i * block; } Right[num] = n; for (int i = 1; i <= n; ++i) { belong[i] = (i-1) / block + 1; }}inline int read(void){ int ret = 0, flag = 1; char c = getchar(); while (c > '9' || c < '0') { if (c == '-') { flag = -1; } c = getchar(); } while ('0' <= c && c <= '9') { ret = ret * 10 + c - '0'; c = getchar(); } return ret * flag;}
3、CDOJ 1324 卿学姐与公主
#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>#include <bitset>#include <ctime>using namespace std;#define REP(i, n) for (int i = 0; i < (n); ++i)typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;typedef pair<int, int> Pair;const ull mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 1e5 + 10;const int maxblock = 400;ll hurt[maxn], belong[maxn], Left[maxblock], Right[maxblock], Max[maxblock];ll N, Q, t, p, x, L, R, num, block;ll read(void);void build(void);void update(void);ll query(void);int main(){#ifdef __AiR_H freopen("in.txt", "r", stdin);#endif // __AiR_H N = read(), Q = read(); while (Q--) { t = read(); if (t == 1) { p = read(), x = read(); update(); } else { L = read(), R = read(); printf("%lld\n", query()); } } return 0;}ll query(void){ ll ans = 0; if (belong[L] == belong[R]) { for (int i = L; i <= R; ++i) { ans = max(ans, hurt[i]); } } else { for (ll i = L; i <= Right[belong[L]]; ++i) { ans = max(ans, hurt[x]); } for (ll i = belong[L] + 1; i < belong[R]; ++i) { ans = max(ans, Max[i]); } for (ll i = Left[belong[R]]; i <= R; ++i) { ans = max(ans, hurt[i]); } } return ans;}void update(void){ hurt[p] += x; Max[belong[p]] = max(Max[belong[p]], hurt[p]);}void build(void){ block = sqrt(N); num = N / block; if (N%block) { ++num; } for (ll i = 1; i <= num; ++i) { Left[i] = (i-1) * block + 1, Right[i] = i * block; } Right[num] = N; for (ll i = 1; i <= N; ++i) { belong[i] = (i-1) / block + 1; }}ll read(void){ ll ret = 0; char c = getchar(); while (c < '0' || c > '9') { c = getchar(); } while ('0' <= c && c <= '9') { ret = ret * 10 + c - '0'; c = getchar(); } return ret;}
4、BZOJ 4028 [HEOI2015] 公约数数列
参考:http://www.cnblogs.com/qscqesze/p/5203524.html
#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <set>#include <cmath>#include <cctype>#include <bitset>#include <ctime>using namespace std;#define REP(i, n) for (int i = 0; i < (n); ++i)typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;typedef pair<int, int> Pair;const ll maxn = 1e5 + 10;const ll maxblock = 400;ll belong[maxn], Left[maxblock], Right[maxblock], a[maxn], gcd[maxn], Xor[maxn];ll block, num, n, id, q, x;char cmd[10];set<ll> Set[maxblock];void build(ll t);int main(){#ifdef __AiR_H freopen("in.txt", "r", stdin);#endif // __AiR_H scanf("%lld", &n); for (ll i = 1; i <= n; ++i) { scanf("%lld", &a[i]); } block = sqrt(n); num = n / block; if (n%block) { ++num; } for (ll i = 1; i <= num; ++i) { Left[i] = (i-1) * block + 1, Right[i] = i * block; } Right[num] = n; for (ll i = 1; i <= n; ++i) { belong[i] = (i-1) / block + 1; } for (ll i = 1; i <= num; ++i) { build(i); } scanf("%lld", &q); while (q--) { scanf("%s", cmd); if (cmd[0] == 'M') { scanf("%lld %lld", &id, &x), ++id; a[id] = x; build(belong[id]); } else { scanf("%lld", &x); ll flag = 0, lgcd = 0, lxor = 0; for (ll i = 1; i <= num; ++i) { ll gcd_t = __gcd(lgcd, gcd[Right[i]]); if (gcd_t != lgcd) { for (ll j = Left[i]; j <= Right[i]; ++j) { if ((lxor ^ Xor[j]) * __gcd(lgcd, gcd[j]) == x) { flag = j; break; } } if (flag) { break; } } else { if (x%gcd_t == 0 && Set[i].count((x/gcd_t) ^ lxor)) { for (ll j = Left[i]; j <= Right[i]; ++j) { if ((lxor ^ Xor[j]) * lgcd == x) { flag = j; break; } } if (flag) { break; } } } lgcd = gcd_t, lxor ^= Xor[Right[i]]; } if (flag) { printf("%lld\n", flag-1); } else { printf("no\n"); } } } return 0;}void build(ll t){ Set[t].clear(); gcd[Left[t]] = Xor[Left[t]] = a[Left[t]]; Set[t].insert(Xor[Left[t]]); for (ll i = Left[t] + 1; i <= Right[t]; ++i) { gcd[i] = __gcd(gcd[i-1], a[i]), Xor[i] = Xor[i-1] ^ a[i]; Set[t].insert(Xor[i]); }}
- 块状链表(分块)2016.10.3
- 初识块状数组/块状链表(讲解+ 例题)
- POJ-2887(块状链表)
- [BZOJ1507][NOI2003]Editor(块状链表)
- [BZOJ3337]ORZJRY I(块状链表)
- poj3580:SuperMemo(块状链表/Splay)
- 块状链表
- 块状链表 poj2887
- 块状链表
- 数据结构:块状链表
- 数据结构:块状链表
- java 块状链表
- 块状链表
- 块状链表
- 块状链表
- *块状链表
- POJ2887【块状链表】
- 块状链表模板
- PAT乙级.1034. 有理数四则运算(20)
- jquery 获取验证码倒计时60s
- 解决unsuccessfulbuild”,因为已指定“AlwaysCreate”
- Android Handler : Handler为什么需要是static的 (二)
- 继续杂
- 块状链表(分块)2016.10.3
- 在自己的电脑上搭建服务器,发布自己的网站(学习之用)
- Linux内核的Oops
- Mongodb 安装过程与服务无法启动100、48问题
- 115个Java面试题和答案——终极列表(上)
- 树形DP(工人的请愿书,uva 12186)
- Reactative 网络请求
- 关于swift中KVO的简单使用
- 将MongoDB服务器设置成Windows启动服务(win10)