題解 P4008 【[NOI2003]文本編輯器】
阿新 • • 發佈:2019-04-25
erase because clu reg ons baidu printf merge str
塊狀鏈表及其應用
思路樓上已經說的很清楚了
看代碼註釋
代碼很醜
#include<cstdio> #include<cctype> #include<cstring> //#define gc() getchar() #define MAXIN 100000 #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) const int N=1024*1024*2+5; const int MaxSize=/*1700*/4500,MaxNum=/*1700*2*/N*2/MaxSize+100; int num,nxt[MaxNum],sz[MaxNum],pool[MaxNum]; char data[MaxNum][MaxSize],str[N],IN[MAXIN],*SS=IN,*TT=IN; inline int read() { int now=0,f=1; register char c=gc(); for(; !isdigit(c); c=gc()) if(c==‘-‘) f=-1; for(; isdigit(c); now=now*10+c-‘0‘,c=gc()); return now*f; } inline int New_Block() { return pool[++num]; } inline void Del_Block(int v) { pool[num--]=v; } void Init() { for(int i=1; i<MaxNum; ++i) pool[i]=i; sz[0]=0, nxt[0]=-1;//新建一個0節點,方便 表頭就是0 } void Merge(int cur,int Nxt) { memcpy(data[cur]+sz[cur],data[Nxt],sz[Nxt]); nxt[cur]=nxt[Nxt], sz[cur]+=sz[Nxt]; Del_Block(Nxt); } void Maintain() { for(int cur=0,Nxt=nxt[0]; ~cur; cur=nxt[cur],Nxt=nxt[cur]) while((~Nxt) && sz[cur]+sz[Nxt]<=MaxSize) Merge(cur,Nxt), Nxt=nxt[cur];//最好不用nxt[Nxt],因為已經合並、刪掉了,雖然不影響答案,但還是不該寫 } int Get_Index(int &pos) { //找到pos所在的塊,並將pos定位為塊內位置 int cur=0; while((~cur) && pos>sz[cur])//把cur定位到某一塊的末尾,不用下一塊開頭了(pos>=sz) pos-=sz[cur], cur=nxt[cur]; return cur; } void Update(int cur,int Nxt,int len,char *s) { //給新的塊Nxt設置數據及指針 nxt[Nxt]=nxt[cur], nxt[cur]=Nxt, sz[Nxt]=len; memcpy(data[Nxt],s,len); } void Split(int cur,int pos) { if(cur==-1||pos==sz[cur]) return;//不能判!pos!因為後邊會直接用nxt[cur],不分裂會跳過該塊;而在=sz時不分是沒問題的 int Nxt=New_Block(); Update(cur,Nxt,sz[cur]-pos,data[cur]+pos); sz[cur]=pos; } void Insert(int pos,int len) { int cur=Get_Index(pos),sum=0,Nxt; Split(cur,pos); while(sum+MaxSize<=len) { Nxt=New_Block(); Update(cur,Nxt,MaxSize,str+sum);//先分成盡可能多的整塊 sum+=MaxSize, cur=Nxt; } if(len-sum)//剩余的單獨放到一塊 Nxt=New_Block(), Update(cur,Nxt,len-sum,str+sum); Maintain(); } void Erase(int pos,int len) { int cur=Get_Index(pos),Nxt; Split(cur,pos); Nxt=nxt[cur];//because of here while((~Nxt) && len>sz[Nxt]) len-=sz[Nxt], Del_Block(Nxt), Nxt=nxt[Nxt]; Split(Nxt,len); Del_Block(Nxt), nxt[cur]=nxt[Nxt]; Maintain(); } void Get_Data(int pos,int len) { int cur=Get_Index(pos),sum=sz[cur]-pos; if(len<sum) sum=len; memcpy(str,data[cur]+pos,sum); cur=nxt[cur]; while((~cur) && sum+sz[cur]<=len) memcpy(str+sum,data[cur],sz[cur]), sum+=sz[cur] ,cur=nxt[cur]; if((~cur) && len-sum) memcpy(str+sum,data[cur],len-sum); str[len]=‘\0‘; printf("%s\n",str); } inline char Get_opt() { register char c=gc(); while(c!=‘M‘&&c!=‘I‘&&c!=‘D‘&&c!=‘G‘&&c!=‘P‘&&c!=‘N‘) c=gc(); return c; } int main() { Init(); int t=read(),pos=0,len; char s[10]; while(t--) { switch(Get_opt()) { case ‘M‘: pos=read(); break; case ‘I‘: len=read(); for(int i=0; i<len; ++i) { str[i]=gc(); if(str[i]<32||str[i]>126) --i; } Insert(pos,len); break; case ‘D‘: len=read(),Erase(pos,len); break; case ‘G‘: len=read(),Get_Data(pos,len); break; case ‘P‘: --pos; break; case ‘N‘: ++pos; break; } } return 0; }
可以看看這道題
題解 P4008 【[NOI2003]文本編輯器】