UVA 11996 Jewel Magic Splay+Hash
对于lcs,用Splay维护区间的Hash值,hash(i,i+L)与hash(j,j+L)相等则字符串相等, 利用二分可快速判断出后缀i与后缀j的LCS。
对于翻转操作。同时维护区间hash值与区间逆序列的hash值,对区间节点翻转时交换两个hash值。
.......WA了两天最后才发现模板的init没有对整个区间splay...
------------------------
#include <iostream> #include <ctime> #include <cstdlib> #include <cstdio> #include <cstring> #include <vector> using namespace std; typedef unsigned long long uLL; const int MAX_N = 450000 + 10; const int INF = ~0U >> 1; const int SEED = 7; uLL xp[MAX_N]; char s[MAX_N]; struct Node{ Node *ch[2],*pre;//左右子树,父节点 int val;//关键字 int size;//以它为根的子树的总结点数 uLL hash;//该子树对应序列的hash值 uLL rush;//翻转序列的hash bool rev;//翻转标记 Node(){ size=hash=rush=0; val=0; } void revIt(){ rev^=1; swap(hash,rush); } void upd(){ size=ch[0]->size+ch[1]->size+1; hash=ch[0]->hash+val*xp[ch[0]->size]+ch[1]->hash*xp[ch[0]->size+1]; rush=ch[1]->rush+val*xp[ch[1]->size]+ch[0]->rush*xp[ch[1]->size+1]; } void pushdown(); }Tnull,*null=&Tnull; void Node::pushdown(){ if (rev){ for (int i=0;i<2;i++) if (ch[i]!=null) ch[i]->revIt(); swap(ch[0],ch[1]); rev = 0; } } struct Splay{ Node nodePool[MAX_N],*cur;//内存分配 Node* root;//根 Splay(){ cur=nodePool; root=null; } //清空内存,init()调用 void clear(){ cur=nodePool; root=null; } //新建节点,build()用 Node* newNode(int v,Node* f){ cur->ch[0]=cur->ch[1]=null; cur->size=1; cur->val=v; cur->hash=0; cur->rush=0; cur->rev=0; cur->pre=f; return cur++; } //构造区间[l,r]中点m,init()使用 Node* build(int l,int r,Node* f){ if(l>r) return null; int m=(l+r)>>1; Node* t=newNode(s[m]-'0',f); t->ch[0]=build(l,m-1,t); t->ch[1]=build(m+1,r,t); t->upd(); return t; } //旋转操作,c=0表示左旋,c=1表示右旋 void rotate(Node* x,int c){ Node* y=x->pre; y->pushdown(); x->pushdown(); //先将y结点的标记向下传递(因为y在上面) y->ch[!c]=x->ch[c]; if (x->ch[c]!=null) x->ch[c]->pre=y; x->pre=y->pre; if (y->pre!=null) { if (y->pre->ch[0]==y) y->pre->ch[0]=x; else y->pre->ch[1]=x; } x->ch[c]=y; y->pre=x; y->upd();//维护y结点 if (y==root) root=x; } //Splay操作,表示把结点x转到结点f的下面 void splay(Node* x,Node* f){ x->pushdown();//下传x的标记 while (x->pre!=f){ if (x->pre->pre==f){//父节点的父亲为f,执行单旋 if (x->pre->ch[0]==x) rotate(x,1); else rotate(x,0); }else{ Node *y=x->pre,*z=y->pre; if (z->ch[0]==y){ if (y->ch[0]==x) rotate(y,1),rotate(x,1);//一字型旋转 else rotate(x,0),rotate(x,1);//之字形旋转 }else{ if (y->ch[1]==x) rotate(y,0),rotate(x,0);//一字型旋转 else rotate(x,1),rotate(x,0);//之字形旋转 } } } x->upd();//最后再维护X结点 } //找到处在中序遍历第k个结点,并将其旋转到结点f的下面 void select(int k,Node* f){ int tmp; Node* x=root; x->pushdown(); k++;//空出虚拟节点 for(;;){ x->pushdown(); tmp=x->ch[0]->size; if (k==tmp+1) break; if (k<=tmp) x=x->ch[0]; else{ k-=tmp+1; x=x->ch[1]; } } splay(x,f); } //选择[l,r] Node*&get(int l, int r){ select(l-1,null); select(r+1,root); return root->ch[1]->ch[0]; } //翻转[l,r] void reverse(int l,int r){ Node* o=get(l,r); o->rev^=1; splay(o,null); } //剪切出[l,r]到s1 void split(int l,int r,Node*&s1) { Node* tmp=get(l,r); s1=tmp; root->ch[1]->ch[0]=null; splay(root->ch[1],null); } void del(int p){ select(p-1,null); select(p+1,root); root->ch[1]->ch[0]=null; splay(root->ch[1],null); } void insert(int p,int v){ select(p,null); select(p+1,root); root->ch[1]->ch[0]=newNode(v,root->ch[1]); splay(root->ch[1]->ch[0],null); } //gethash uLL hash(int i,int L){ Node* o=get(i,i+L-1); return o->hash; } //LCS int lcs(int i,int j) { int len=root->size-2; int L=1,R=len-max(i,j)+1; int ans=0; while (L<=R){ int M=L+(R-L)/2; if (hash(i,M)==hash(j,M)){ ans=M; L=M+1; } else{ R=M-1; } } return ans; } //初始化 void init(int n){ clear(); root=newNode(0,null); root->ch[1]=newNode(0,root); root->ch[1]->ch[0]=build(1,n,root->ch[1]); splay(root->ch[1]->ch[0],null); } //输出中序遍历,debug用 void show(Node* rt){ if (rt==null) return; if (rt->ch[0]!=null) show(rt->ch[0]); printf("rt=%d size=%d\n",rt->val,rt->size); if (rt->ch[1]!=null) show(rt->ch[1]); } //按序输出 void output(int l,int r){ for (int i=l;i<=r;i++){ select(i,null); cout<<root->val<<" "; } cout<<endl; } }T; int n,m; int main() { int cd; int num; while (~scanf("%d%d",&n,&m)) { scanf("%s",(s+1)); xp[0]=1; for (int i=1;i<n+m+3;i++) xp[i]=xp[i-1]*SEED; T.init(n); num=n; while (m--) { scanf("%d",&cd); if (cd==1) { int p,c; scanf("%d%d",&p,&c); T.insert(p,c); num++; } if (cd==2) { int p; scanf("%d",&p); T.del(p); num--; } if (cd==3) { int p1,p2; scanf("%d%d",&p1,&p2); T.reverse(p1,p2); } if (cd==4) { int p1,p2; scanf("%d%d",&p1,&p2); printf("%d\n",T.lcs(p1,p2)); } } } return 0; }