题目描述
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
]
)
<
s
i
z
e
[
a
]
rand()\%(size[a]+size[b])<size[a]
rand()%(size[a]+size[b])<size[a]
这样可以使保证子树较大的树高概率被放在上面,使树高均摊
l
o
g
  
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