题目链接:BZOJ1507
【分析】最近在学分块,碰到这题块状链表,手写了一下,有点烦,好久才写对,然后发现有rope这么一个容器,虽然不是标准库的,但是在g++里面而且比赛没有被禁用,所以也写了一下,果然蛮好用的,据说它的操作很多都是logn的。
【AC CODE(块状链表)】436ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 2*1024*1024+10, SIZE = 9000;
char buf[MAXN], *ps = buf, *pe = ps+1;
inline void rnext()
{
if(++ps == pe)
pe = (ps=buf)+fread(buf,1,sizeof(buf),stdin);
}
inline int get_int()
{
do{
rnext();
}while(!isdigit(*ps));
int ans = 0;
do{
ans = (ans<<1)+(ans<<3)+*ps-48;
rnext();
}while(isdigit(*ps));
return ans;
}
inline void get_str(char *s)
{
do{
rnext();
}while(!isalpha(*ps));
int cnt = 0;
do{
s[cnt++] = *ps;
rnext();
}while(isalpha(*ps));
s[cnt] = 0;
}
struct NODE{
char c[SIZE+10];
int len;
NODE *next;
NODE()
{
c[0] = len = 0;
next = NULL;
}
}*rt;
int p;
char str[MAXN], op[100];
void read(int len)
{
int cnt = 0;
while(cnt < len)
{
rnext();
int ch = *ps;
if(32 <= ch && 126 >= ch)
str[cnt++] = ch;
}
str[cnt] = 0;
}
NODE* find_block(int pos, int &k)//找到位置pos在哪个块,并且返回是该块中的第k个字符
{
int sum = 0;
NODE * tmp = rt;
while(tmp->next)
{
if(sum + tmp->len >= pos) break;
sum += tmp->len;
tmp = tmp->next;
}
k = pos-sum;
return tmp;
}
void split(NODE *u,int k,NODE *&r)//把u在第k个位置分裂成u和r,并且u->next == r
{
r = new NODE();
r->next = u->next;
u->next = r;
strcpy(r->c,u->c+k);
r->len = u->len-k;
u->c[k] = 0;
u->len = k;
}
void merge(NODE *u, NODE *r)//把u后面的r合并到u,r必须是n->next,且r不为空
{
strcat(u->c,r->c);
u->len += r->len;
u->next = r->next;
free(r);
r = NULL;
}
void insert(int len)//在p后面插入len个字符
{
int k;
NODE *u = find_block(p,k), *r;
if(k == u->len)//刚好在块u后面插入
r = u->next;
else
split(u,k,r);//否则需要分裂u
//在u和r之间插入若干块总长度为len
NODE *tmp = u;
int cnt = 0;
while(len-cnt >= SIZE)
{
NODE *now = new NODE();
strncpy(now->c,str+cnt,SIZE);
now->c[SIZE] = 0;
now->len = SIZE;
now->next = tmp->next;
tmp->next = now;
tmp = now;
cnt += SIZE;
}
if(len-cnt)
{
NODE *now = new NODE();
strcpy(now->c,str+cnt);
now->len = len-cnt;
now->next = tmp->next;
tmp->next = now;
tmp = now;
cnt = len;
}
//如果有连续的两块大小都小于SIZE/2则合并
if(rt != u && u->len <= (SIZE>>1) && u->next && u->next->len <= (SIZE>>1))
{
if(tmp == u->next)
merge(u,u->next), tmp = u;
else merge(u,u->next);
}
if(tmp != rt && tmp->len <= (SIZE>>1) && r && r->len <= (SIZE>>1)) merge(tmp,r);
}
void del(int len)//删除p后面的len个字符
{
int sk,ek;
NODE *st = find_block(p,sk), *sr;
NODE *ed = find_block(p+len,ek), *er;
split(ed,ek,er);
split(st,sk,sr);
NODE *tmp = st->next;
while(tmp != er)
{
NODE *buf = tmp;
tmp = tmp->next;
free(buf);
}
st->next = er;
if(st->len <= (SIZE>>1) && er->len <= (SIZE>>1)) merge(st,er);
}
void get(int len)
{
int k, cnt = 0;
NODE *now = find_block(p+1,k);
while(now && cnt < len)
{
for(int i = k-1;i < now->len && cnt < len; i++) putchar(now->c[i]), cnt++;
now = now->next;
k = 1;
}
putchar('\n');
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
//freopen("d:\\out.txt", "w", stdout);
#endif
int q = get_int();
p = 0;
rt = new NODE();
while(q--)
{
get_str(op);
if('I' == op[0])
{
int len = get_int();
read(len);
insert(len);
}
else if('M' == op[0])
{
p = get_int();
}
else if('D' == op[0])
{
int len = get_int();
del(len);
}
else if('G' == op[0])
{
int len = get_int();
get(len);
}
else if('P' == op[0])
{
p--;
}
else p++;
}
return 0;
}
【AC CODE(rope)】412ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 2*1024*1024+10, SIZE = 7000;
char buf[MAXN], *ps = buf, *pe = ps+1;
inline void rnext()
{
if(++ps == pe)
pe = (ps=buf)+fread(buf,1,sizeof(buf),stdin);
}
inline int get_int()
{
do{
rnext();
}while(!isdigit(*ps));
int ans = 0;
do{
ans = (ans<<1)+(ans<<3)+*ps-48;
rnext();
}while(isdigit(*ps));
return ans;
}
inline void get_str(char *s)
{
do{
rnext();
}while(!isalpha(*ps));
int cnt = 0;
do{
s[cnt++] = *ps;
rnext();
}while(isalpha(*ps));
s[cnt] = 0;
}
int p;
char str[MAXN], op[100];
rope<char> rp;
void read(int len)
{
int cnt = 0;
while(cnt < len)
{
rnext();
int ch = *ps;
if(32 <= ch && 126 >= ch)
str[cnt++] = ch;
}
str[cnt] = 0;
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
//freopen("d:\\out.txt", "w", stdout);
#endif
int q = get_int();
p = 0;
rp.clear();
while(q--)
{
get_str(op);
if('I' == op[0])
{
int len = get_int();
read(len);
rp.insert(p,str);
}
else if('M' == op[0])
{
p = get_int();
}
else if('D' == op[0])
{
int len = get_int();
rp.erase(p,len);
}
else if('G' == op[0])
{
int len = get_int();
rp.copy(p,len,str);
str[len] = 0;
puts(str);
}
else if('P' == op[0])
{
p--;
}
else p++;
}
return 0;
}