【NOI2003】 editor

【题目大意】

要求一种数据结构,能够支持

(1)在某个位置插入长度为n的字符串

(2)删除从某个位置开始的长度为n的字符串

(3)输出从某个位置开始的长度为n的字符串


【分析】

块状链表

很裸的一道题,练练手。

要注意几点细节:

(1)空间可以循环使用

(2)注意随时保证复杂度,即合并小区间


【代码】

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rrep(i,b,a) for(int i=(b);i>=(a);--i)
#define sf scanf
#define pf printf
#define MAXL (2*1024*1024+10)
#define MAXBLOCK 1500
#define BLOCKSIZE 1500

int N;
int freepos;
int freelist[MAXBLOCK];
int sz[MAXBLOCK];
int next[MAXBLOCK];
char str[MAXL];
char data[MAXBLOCK][BLOCKSIZE];

void Read(int& x,bool mark=0){
	char tt=getchar();
	for(;tt<'0'||'9'<tt;tt=getchar()) if(tt=='-') mark=1;
	for(x=0;'0'<=tt&&tt<='9';x=(x<<1)+(x<<3)+tt-'0',tt=getchar());
	x=mark?-x:x;
}

int Newnode(){
	return freelist[freepos++];
}

void Delnode(int t){
	return (void)(freelist[--freepos]=t);
}

void Find(int& p,int& b){
	for(b=0;b!=-1&&p>sz[b];b=next[b]) p-=sz[b];
}

void Fillblock(int b,int n,char* str,int e){
	if(b==-1) return;
	next[b]=e;
	sz[b]=n;
	memcpy(data[b],str,n);
}

void Split(int b,int p){
	if(b==-1||p==sz[b]) return;
	int t=Newnode();
	Fillblock(t,sz[b]-p,data[b]+p,next[b]);
	next[b]=t;
	sz[b]=p;
}

void Maintainlist(int b){
	for(;b!=-1;b=next[b]){
		for(int t=next[b];t!=-1&&sz[b]+sz[t]<=BLOCKSIZE;t=next[b]){
			memcpy(data[b]+sz[b],data[t],sz[t]);
			sz[b]+=sz[t];
			next[b]=next[t];
			Delnode(t);
		}
	}
}

void Insert(int p,int n,char* str){
	int b,t,i;
	Find(p,b);
	Split(b,p);
	for(i=0;i+BLOCKSIZE<=n;i+=BLOCKSIZE){
		t=Newnode();
		Fillblock(t,BLOCKSIZE,str+i,next[b]);
		next[b]=t;
		b=t;
	}
	if(n-i){
		t=Newnode();
		Fillblock(t,n-i,str+i,next[b]);
		next[b]=t;
	}
	Maintainlist(b);
}

void Erase(int p,int n){
	int b,e;
	Find(p,b);
	Split(b,p);
	for(e=next[b];e!=-1&&n>sz[e];e=next[e]) n-=sz[e];
	Split(e,n);
	e=next[e];
	for(int t=next[b];t!=e;t=next[b]){
		next[b]=next[t];
		Delnode(t);
	}
	Maintainlist(b);
}

void Get(int p,int n,char* str){
	int b,t,i;
	Find(p,b);
	i=min(n,sz[b]-p);
	memcpy(str,data[b]+p,i);
	for(t=next[b];t!=-1&&i+sz[t]<=n;i+=sz[t],t=next[t]){
		memcpy(str+i,data[t],sz[t]);
	}
	if(n-i&&t!=-1) memcpy(str+i,data[t],n-i);
	str[n]='\0';
}

void Init(){
	Read(N);
	rep(i,1,MAXBLOCK-1) freelist[i]=i;
	freepos=1;
	next[0]=-1;
	sz[0]=0;
}

void Solve(){
	char order[10];
	int cur=0,n;
	while(N--){
		sf("%s",order);
		switch(order[0]){
			case 'M':Read(cur);break;
			case 'I':
				Read(n);char c;
				rep(i,0,n-1){
					c=getchar();
					str[i]=c;
					if(c=='\n') --i;
				}
				Insert(cur,n,str);
				break;
			case 'D':
			    Read(n);
				Erase(cur,n);
				break;
			case 'G':
			    Read(n);
				Get(cur,n,str);
				pf("%s\n",str);
				break;
			case 'P':--cur;break;
			case 'N':++cur;break;
		}
	}
}

int main(){
	Init();
	Solve();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值