UVA 11996 Jewel Magic Splay+Hash
2013-08-27 20:41
375 查看
Description
and ask me, what is the length of the longest common prefix (LCP) of jewel strings starting from these two jewels, I can answer your question instantly. Can you do better than me?
Formally, you'll be given a string of 0 and 1. You're to deal with four kinds of operations (in the following descriptions, L denotes the current length of the string, and jewel positions are number 1 to L numbered
from left to right):
Insert a jewel c after position p (0<=p<=L. p=0 means insert before the whole string). c=0 means emerald, c=1 represents pearl.
Remove the jewel at position p (1<=p<=L).
Reverse the part starting from position p1, ending at position p2 (1<=p1 < p2<=L)
Output the LCP length of jewel strings starting from p1 and p2 (1<=p1 < p2<=L).
a 01 string of length n. Each of the next m lines contains an operation. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.
String after operation 3 7 10: 1000101000100
String after operation 2 9: 100010100100
Rujia Liu's Present 3: A Data Structure Contest Celebrating the 100th Anniversary of Tsinghua University
Special Thanks: Xinhao Yuan, Yao Li, Liang Dun
Note: Please make sure to test your program with the gift I/O files before submitting!
------------------------
对于lcs,用Splay维护区间的Hash值,hash(i,i+L)与hash(j,j+L)相等则字符串相等, 利用二分可快速判断出后缀i与后缀j的LCS。
对于翻转操作。同时维护区间hash值与区间逆序列的hash值,对区间节点翻转时交换两个hash值。
.......WA了两天最后才发现模板的init没有对整个区间splay...
------------------------
Problem J
Jewel Magic
I am a magician. I have a string of emeralds and pearls. I may insert new jewels in the string, or remove old ones. I may even reverse a consecutive part of the string. At anytime, if you point to two jewelsand ask me, what is the length of the longest common prefix (LCP) of jewel strings starting from these two jewels, I can answer your question instantly. Can you do better than me?
Formally, you'll be given a string of 0 and 1. You're to deal with four kinds of operations (in the following descriptions, L denotes the current length of the string, and jewel positions are number 1 to L numbered
from left to right):
1 p c
Insert a jewel c after position p (0<=p<=L. p=0 means insert before the whole string). c=0 means emerald, c=1 represents pearl.
2 p
Remove the jewel at position p (1<=p<=L).
3 p1 p2
Reverse the part starting from position p1, ending at position p2 (1<=p1 < p2<=L)
4 p1 p2
Output the LCP length of jewel strings starting from p1 and p2 (1<=p1 < p2<=L).
Input
There will be several test cases. The first line of each test case contains an integer n and m (1<=n,m<=200,000), where n is the number of pearls initially, m is the number of operations. The next line containsa 01 string of length n. Each of the next m lines contains an operation. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.
Output
For each type-4 operation, output the answer.Sample Input
12 9 000100001100 1 0 1 4 2 6 3 7 10 4 1 7 2 9 4 3 11 4 1 9 4 1 7 4 2 3
Output for the Sample Input
3 6 2 0 3 2
Explanation
String after operation 1 0 1: 1000100001100String after operation 3 7 10: 1000101000100
String after operation 2 9: 100010100100
Rujia Liu's Present 3: A Data Structure Contest Celebrating the 100th Anniversary of Tsinghua University
Special Thanks: Xinhao Yuan, Yao Li, Liang Dun
Note: Please make sure to test your program with the gift I/O files before submitting!
------------------------
对于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; }
相关文章推荐
- UVA 11996 Jewel Magic Splay+Hash
- UVa 11996 Jewel Magic (splay + Hash + 二分)
- UVA 11996 Splay + LCP + Hash + 区间翻转 插入 删除
- Uva 11996 Jewel Magic (Splay)
- UVA - 11996(splay入门)
- UVA 11996 Jewel Magic —— splay、序列的分裂与合并、LCP的哈希算法
- UVA 11996 splay
- UVa11996 splay树(WA)
- UVA 11996 Jewel Magic(splay)
- UVA 11996 Jewel Magic (splay求两个后缀的LCP)
- uva--10282+hash
- BZOJ.1014.[JSOI2008]火星人(Splay 二分 Hash)
- UVA 188 - Perfect Hash
- uva 10391 Compound Words (字符串-hash)
- Uva 10887:Concatenation of Languages(Hash)
- BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )
- Colour Hash (Uva 704 双向bfs)
- UVA 10457 Magic Car——最小瓶颈路
- Uva LA 4513 Stammering Aliens(Follow the example, solve by lcp using hash)
- UVA 11922 Permutation Transformer (Splay树)