jzoj3658. 【NOI2014模拟】文本编辑器(editor)

16 篇文章 0 订阅
4 篇文章 0 订阅

题目描述

Description
在这里插入图片描述
Input
在这里插入图片描述
Output
对于每个询问输出一个字符表示答案。

Sample Input
9
I 0 o
I 0 r
I 0 z
R 1 3
Q 1
D 1 1
Q 1
C 2 2 0
Q 1

Sample Output
orz

Data Constraint
在这里插入图片描述

题解

因为有复制操作,所以要用可持久化平衡树来搞
其它操作相同,复制操作时先复制根,然后取出要复制的节点(split*2),最后插入(split*1,merge*2)

因为是区间操作,所以下传标记时也要新建孩子节点

优化

1、每次如果有标记才下传(新建节点)
2、(自己想的)如果一个节点有多条边指向它时才新建
比较玄学,但很有效
要注意当一个点只剩一个父亲时,记录的父亲可能会错
比如这样
在这里插入图片描述
其中黑色边表示向下指向孩子的边,红色边表示记录的父亲,灰色边表示将要复制的边(即非原本父亲指向它的边)
然后新建节点后变成了这样
在这里插入图片描述
显然下面的节点的父亲错了
解决方法是每次向下走时都将儿子的父亲设为当前点,这样一定能保证其正确性
就算当前的父亲时错的也无所谓,因为最后只剩一个父亲时一定是对的

3、(构思中)每次把下传标记分成左右儿子分别下传,然后再记录每条边出现时复制的原节点,之后只有向某一方向走时才新建节点
不过这样复制信息就会很eggache,反正都过了就无所谓了

4、查找时可以不同新建节点,只需要记录下当前的儿子是否翻转
向下走就异或一下左/右儿子的编号(0/1)

5、随机的值可以不用数组记录,只需要
r a n d ( ) % ( s i z e [ a ] + s i z e [ b ] ) &lt; s i z e [ a ] rand()\%(size[a]+size[b])&lt;size[a] rand()%(size[a]+size[b])<size[a]
这样可以使保证子树较大的树高概率被放在上面,使树高均摊 l o g &ThickSpace; n log\;n logn

6、O3大法好
2000byte的O3问你怕不怕

*7、OJ上的随机数范围是0~2147483647,而本地是0~32767
马德坑了我两个礼拜

code

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define Max 20000001
using namespace std;

int tr[Max][2];
int sum[Max];
int fa[Max];
int num[Max];
bool rev[Max];
int FA[Max]; //nµÄ¸¸Ç׸öÊý
int N,n,Q,i,j,k,l,x,y,z,X,Fs,Ls,I,J,root,Find,Find2,now,fa1,fa2,Root,ROOT,root2;
char type,ch;

inline int getint() {char c; register int ret=0; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; }
inline char getChar()
{
	char ch=getchar();
	for (; ch<'A' || ('Z'<ch && ch<'a') || 'z'<ch; ch=getchar());
	return ch;
}

inline void up(register int t) {sum[t]=sum[tr[t][0]]+sum[tr[t][1]]+1;}
inline void swap(register int &a,register int &b) {int c=a;a=b;b=c;}

inline int copy(register int root)
{
	if (now)
	{
		n++;
		tr[n][0]=tr[root][0]; FA[tr[n][0]]++;
		tr[n][1]=tr[root][1]; FA[tr[n][1]]++;
		num[n]=num[root];
		sum[n]=sum[root];
		rev[n]=rev[root];
	}
	
	return n;
}

inline void down(register int t)
{
	if (rev[t] && t)
	{
		swap(tr[t][0],tr[t][1]);
		
		rev[tr[t][0]]^=1;
		rev[tr[t][1]]^=1;
		rev[t]=0;
	}
}

inline void New(register int t,register int x)
{
	if (t && tr[t][x])
	{
		fa[tr[t][x]]=t;
		
		if (FA[tr[t][x]]>1)//优化2
		{
			FA[tr[t][x]]--;
			
			n++;
			tr[n][0]=tr[tr[t][x]][0]; FA[tr[n][0]]++;
			tr[n][1]=tr[tr[t][x]][1]; FA[tr[n][1]]++;
			sum[n]=sum[tr[t][x]];
			fa[n]=t; //not fa[tr[t][x]]
			num[n]=num[tr[t][x]];
			rev[n]=rev[tr[t][x]];
			FA[n]=1;
			
			tr[t][x]=n;
		}
	}
}

inline void merge(register int Fa,register int son,register int x,register int y)
{
	if (x && rev[x]) New(x,0),New(x,1),down(x);//优化1
	if (y && rev[y]) New(y,0),New(y,1),down(y);
	
	if (rand()%(sum[x]+sum[y])<sum[x])//优化5
	{
		if (Root==-1) Root=x;
		New(x,1);
		
		tr[Fa][son]=x;
		FA[x]+=(!fa[x] && Fa);
		fa[x]=Fa;
		
		if (tr[x][1])
		merge(x,1,tr[x][1],y);
		else
		{
			if (x)
			{
				sum[x]+=sum[y];
				tr[x][1]=y;
			}
			FA[y]+=(!fa[y]);
			fa[y]=x;
		}
	}
	else
	{
		if (Root==-1) Root=y;
		New(y,0);
		
		tr[Fa][son]=y;
		FA[y]+=(!fa[y] && Fa);
		fa[y]=Fa;
		
		if (tr[y][0])
		merge(y,0,x,tr[y][0]);
		else
		{
			if (y)
			{
				sum[y]+=sum[x];
				tr[y][0]=x;
			}
			FA[x]+=(!fa[x]);
			fa[x]=y;
		}
	}
	
	if (Fa) up(Fa);
}

inline void split(register int Fa1,register int Fa2,register int t,register int k) //fa1±íʾºó°ë¶ÎµÄ¸ù£¬fa2±íʾǰ°ë¶ÎµÄ¸ù
{
	if (rev[t]) New(t,0),New(t,1),down(t);
	
	if (sum[tr[t][0]]>=k)
	{
		New(t,0);
		if (!fa1) fa1=t;
		
		if (fa[t])
		{
			FA[t]-=(!Fa1);
			tr[fa[t]][tr[fa[t]][1]==t]=0;
			up(fa[t]);
		}
		
		tr[Fa1][0]=t;
		fa[t]=Fa1;
		
		if (k && tr[t][0])
		split(t,Fa2,tr[t][0],k);
		
		if (Fa1) up(Fa1);
	}
	else
	{
		New(t,1);
		if (!fa2) fa2=t;
		
		if (fa[t])
		{
			FA[t]-=(!Fa2);
			tr[fa[t]][tr[fa[t]][1]==t]=0;
			up(fa[t]);
		}
		
		tr[Fa2][1]=t;
		fa[t]=Fa2;
		
		if (tr[t][1])
		split(Fa1,t,tr[t][1],k-sum[tr[t][0]]-1);
		
		if (Fa2) up(Fa2);
	}
}

inline int find(register int t,register int k,register bool Rev)
{
	Rev^=rev[t]; //优化4
	
	if (sum[tr[t][Rev]]>=k)
	return find(tr[t][Rev],k,Rev);
	else
	if (sum[tr[t][Rev]]+1==k)
	return num[t];
	else
	return find(tr[t][!Rev],k-sum[tr[t][Rev]]-1,Rev);
}

int main()
{
	freopen("editor.in","r",stdin);
	freopen("editor.out","w",stdout);
	
	srand(time(NULL));
	
	Q=getint();
	
	n=0;
	now=0;
	fo(I,1,Q)
	{
		type=getChar();
		switch (type)
		{
			case 'I':
				{
					x=getint();
					ch=getChar();
					
					n++;N=n;
					num[n]=ch-'a';
					sum[n]=1;
					
					if (!now)
					root=N;
					else
					{
						Root=-1;
						if (!x)
						merge(0,0,N,root);
						else
						if (x==now) 
						merge(0,0,root,N);
						else
						{
							fa1=0;fa2=0;
							split(0,0,root,x);
							
							merge(0,0,fa2,N);
							
							ROOT=Root;
							Root=-1;
							merge(0,0,ROOT,fa1);
						}
						
						root=Root;
					}
					
					now++;
					break;
				}
				
			case 'D':
				{
					x=getint();
					y=getint();
					
					j=0;k=0;
					if (x>1)
					{
						fa1=0;fa2=0;
						split(0,0,root,x-1);
						
						j=fa2;
						root=fa1;
					}
					if (y<now)
					{
						fa1=0;fa2=0;
						split(0,0,root,y-x+1);
						
						k=fa1;
					}
					
					if (j && k)
					{
						Root=-1;
						merge(0,0,j,k);
						root=Root;
					}
					else
					if (j) root=j;
					else
					if (k) root=k;
					
					now-=(y-x+1);
					break;
				}
				
			case 'C':
				{
					x=getint();
					y=getint();
					z=getint();
					
					root2=copy(root);
					
					j=0;k=0;
					if (x>1)
					{
						fa1=0;fa2=0;
						split(0,0,root,x-1);
						
						j=fa2;
						root=fa1;
					}
					if (y<now)
					{
						fa1=0;fa2=0;
						split(0,0,root,y-x+1);
						
						k=fa1;
						root=fa2;
					}
					
					Root=-1;
					if (!z)
					merge(0,0,root,root2);
					else
					if (z==now) 
					merge(0,0,root2,root);
					else
					{
						fa1=0;fa2=0;
						split(0,0,root2,z);
						
						merge(0,0,fa2,root);
						
						ROOT=Root;
						Root=-1;
						merge(0,0,ROOT,fa1);
					}
					
					root=Root;
					
					now+=(y-x+1);
					break;
				}
				
			case 'R':
				{
					x=getint();
					y=getint();
					
					j=0;k=0;
					if (x>1)
					{
						fa1=0;fa2=0;
						split(0,0,root,x-1);
						
						j=fa2;
						root=fa1;
					}
					if (y<now)
					{
						fa1=0;fa2=0;
						split(0,0,root,y-x+1);
						
						k=fa1;
						root=fa2;
					}
					
					rev[root]^=1;
					
					Root=-1;
					if (j && k)
					{
						merge(0,0,j,root);
						
						ROOT=Root;
						Root=-1;
						merge(0,0,ROOT,k);
					}
					else
					if (j)
					merge(0,0,j,root);
					else
					if (k)
					merge(0,0,root,k);
					
					if (Root>-1)
					root=Root;
					break;
				}
				
			case 'Q':
				{
					x=getint();
					putchar(find(root,x,0)+'a');
					break;
				}
		}
	}
}

后记

因为没有压代码所以看上去很清真
对着表改真舒服

接下来要开始搞NOIP了

参考

https://blog.csdn.net/jpwang8/article/details/79211007
https://blog.csdn.net/jokerwyt/article/details/81710270

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值