这题我一开始复制模板,用的是指针式splay,微调了一下就交了,发现poj坏了(submmited failed)
今天一看,发现WA了,原来是insert到右子树时忘记把期望插入的位置减去
左儿子的size+1
,改完后T了
百度题解,发现别人都用块状链表,这不科学啊,
logn
怎么可能比
n√
慢这么多(本机测试得耗时至少多一倍),看来splay常数太大
改成手写内存池,更慢了。
改成数组,终于
641ms
,
2602B
AC了。
然后看了看别人代码,有位小哥
266ms
,
993B
AC了,顿觉人生失去希望,为什么一开始要作死写splay
//#pragma GCC optimize("O2")
#include <cstdio>
#include <cstring>
#include <ctime>
const int N=1100000;
int n,x;
char c[N],a[5],b[5];
struct list{
int xb,rt;
struct node{
int l,r,fa,size;
char v;
node(char _v=0):v(_v){size=1,l=r=fa=0;}
}a[N];
void maintain(int i){
a[i].size=a[a[i].l].size+a[a[i].r].size+1;
}
void rorate(int x){
int y=a[x].fa,z=a[y].fa;
if(z){
if(a[z].l==y)a[z].l=x;
else a[z].r=x;
}
a[x].fa=z;
a[y].fa=x;
if(a[y].l==x){
a[a[x].r].fa=y;
a[y].l=a[x].r;
a[x].r=y;
}else{
a[a[x].l].fa=y;
a[y].r=a[x].l;
a[x].l=y;
}
maintain(y);
maintain(x);
}
void splay(int x){
while(a[x].fa){
int y=a[x].fa,z=a[y].fa;
if(z){
if((a[y].l==x)^(a[z].l==y))rorate(x);
else rorate(y);
}
rorate(x);
}
rt=x;
}
char& operator[](int i){//1<=i<=rt->size
int x=rt;
for(;;){
int y=a[a[x].l].size+1;
if(y>i)x=a[x].l;
else if(y<i){
i-=y;
x=a[x].r;
}else return a[x].v;
}
}
int ins(int&aa,int b,char c){
if(!aa)return a[aa=++xb]=node(c),xb;
int x=a[a[aa].l].size,u;
if(b<=x){
u=ins(a[aa].l,b,c);
maintain(aa);
}else{
u=ins(a[aa].r,b-x-1,c);
maintain(aa);
}
if(!a[u].fa)a[u].fa=aa;
return u;
}
inline void push_back(char c){
int x=rt;
while(a[x].r)++a[x].size,x=a[x].r;
a[a[x].r=++xb]=node(c);
a[a[x].r].fa=x;
splay(a[x].r);
}
void insert(int i,char c){
if(i>a[rt].size)push_back(c);
else splay(ins(rt,i,c));
}
void build(int fa,int&x,char*first,char*last){
a[x=++xb].fa=fa;
char *m=first+((last-first)>>1);
a[x].v=*m;
if(m!=first)build(x,a[x].l,first,m-1);
if(m!=last)build(x,a[x].r,m+1,last);
maintain(x);
}
void operator=(char*c){
build(0,rt,c,c+strlen(c)-1);
}
void midout(int i){
if(i){
midout(a[i].l);
putchar(a[i].v);
midout(a[i].r);
}
}
}l;
int main(){
//freopen("a.txt","r",stdin);
//freopen("wa.txt","w",stdout);
scanf("%s%d",c+1,&n);
l.a[0].size=0;
l=c+1;
while(n--){
scanf("%s",a);
if(*a=='I'){
scanf("%s%d",b,&x);
l.insert(x-1,*b);
}else{
scanf("%d",&x);
putchar(l[x]);
putchar('\n');
}
}
return 0;
}
upd:后来我也用vector,写了遍块链,块大小设为3500时耗时391ms,代码长度621B
#include<stdio.h>
#include<vector>
using std::vector;
const int sz=3500,bs=550;
int n,i,xb,x,l;
char a[5],b[5],c[sz*bs];
vector<char> v[bs];
int main(){
scanf("%s",c+1);
xb=1;
for(i=1;c[i];++i){
v[xb].push_back(c[i]);
if(v[xb].size()==sz)++xb;
}
l=i-1;
scanf("%d",&n);
while(n--){
scanf("%s",a);
if(*a=='Q'){
scanf("%d",&x);
for(i=1;x>(int)v[i].size();++i)x-=v[i].size();
putchar(v[i][x-1]),putchar('\n');
}else{
scanf("%s%d",b,&x);
if(x<=l){
for(i=1;x>(int)v[i].size();++i)x-=v[i].size();
v[i].insert(v[i].begin()+x-1,*b);
}else v[xb].push_back(*b);
++l;
}
}
return 0;
}