题目:
http://poj.org/problem?id=2887
题意:
初始给定一个字符串,然后有两种操作:
I ch p
在第
p
个字符前插入字符
思路:
用的块状链表。块状链表的基本操作有定位、插入、分裂、合并和删除,各个操作均为 O(n√) 。这个题算是裸题了,留个模板
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1000000 + 10, M = 2000 + 10;
queue<int> que;
int head;
char str[N];
struct block
{
int sz, next;
char s[M];
void init()
{
sz = 0, next = -1;
}
}g[M];
int new_block() //分配新块
{
int t = que.front(); que.pop();
g[t].init();
return t;
}
void del_block(int t) //删除块
{
que.push(t);
}
void block_split(int idx, int k) //块分裂
{
int tot = new_block();
memcpy(g[tot].s, g[idx].s + k, sizeof(char) * (g[idx].sz - k));
g[tot].sz = g[idx].sz - k, g[idx].sz = k;
g[tot].next = g[idx].next, g[idx].next = tot;
}
void block_init(char *str) //初始化
{
while(! que.empty()) que.pop();
for(int i = 0; i < M; i++) que.push(i);
head = new_block();
int idx = head;
int len = strlen(str), i = 0;
while(i < len)
{
int sz = min(M, len - i);
memcpy(g[idx].s, str + i, sizeof(char) * sz);
g[idx].sz = sz;
i += sz;
if(i < len)
{
int tot = new_block();
g[idx].next = tot;
idx = g[idx].next;
}
}
for(int i = head; i != -1; i = g[i].next)
if(g[i].sz == M) block_split(i, M>>1); //块满,及时进行分裂
}
void block_locate(int &idx, int &k) //块定位
{
while(idx != -1 && k > g[idx].sz)
k -= g[idx].sz, idx = g[idx].next;
}
char block_query(int k)
{
int idx = head;
block_locate(idx, k);
return g[idx].s[k-1];
}
void block_insert(int k, char ch) //插入
{
int idx = head;
block_locate(idx, k);
if(k >= g[idx].sz) g[idx].s[g[idx].sz] = ch;
else
{
for(int i = g[idx].sz-1; i >= k; i--)
g[idx].s[i+1] = g[idx].s[i];
g[idx].s[k] = ch;
}
g[idx].sz++;
if(g[idx].sz == M) block_split(idx, M>>1);
}
int main()
{
char op, ch;
int n, p;
while(~ scanf("%s", str))
{
block_init(str);
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf(" %c", &op);
if(op == 'Q')
{
scanf("%d", &p);
printf("%c\n", block_query(p));
}
else
{
scanf(" %c%d", &ch, &p);
block_insert(p-1, ch);
}
}
}
return 0;
}