uva11996 - Jewel Magic 伸展树
2014-12-23 15:42
459 查看
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 jewels and ask me, what is the length of the longestcommon 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 contains a 01 string of length n. Each of the next mlines 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
长度为N的0,1串,四种操作。
1 p c,在第p个字符之后插入字符c。
2 p ,删除第p个字符,后面的字符往前移。
3 p1 p2,反转第p1到p2个字符。
4 p1 p2,输出p1开始和p2开始的两个后缀的LCP。
首先建立虚拟开始结点和结束结点,root是开始结点,root->ch[1]是结束结点,以root->ch[1]->ch[0]为根建立01串的树,这个可以像线段树那样二分建立。对于1,2,3操作,都用range截出相应的一段操作就行了,对于4操作,可以二分长度L,然后截出(x,x+L)和(y,y+L),判断这两个串相不相等,用hash值来判断比较好,因此对于每个结点我们还需要h1和h2代表以这个结点为根的串的正向hash值和倒过来的hash值,维护的时候根据hash值的定义有h1=ch[0]->h1*powers[ch[1]->s+1]+v*powers[ch[1]->s]+ch[1]->h1,h2=ch[1]->h2*powers[ch[0]->s+1]+v*powers[ch[0]->s]+ch[0]->h2,这样我们只需要比较截出来的两段hash值是否相等,其实只用比较h1就行了,但为了防止冲突发生,把h1和h2都比较一下更保险。
#include<iostream> #include<queue> #include<cstring> #include<cstdio> #include<cmath> #include<set> #include<map> #include<vector> #include<stack> #include<algorithm> #define INF 0x3f3f3f3f #define eps 1e-9 #define MAXNODE 105 #define MOD 10000007 #define SIGMA_SIZE 4 typedef long long LL; using namespace std; const int MAXN=400020; unsigned powers[MAXN]; struct Node *null,*pit; struct Node{ Node* ch[2]; int s; int flip; int v; unsigned h1,h2; Node(){} Node(int v):s(1),flip(0),v(v),h1(v),h2(v){ ch[0]=ch[1]=null; } void* operator new(size_t){ return pit++; } int cmp(int k) const{ int d=k-ch[0]->s; if(d==1) return -1; return d<=0?0:1; } void maintain(){ s=ch[0]->s+ch[1]->s+1; h1=ch[0]->h1*powers[ch[1]->s+1]+v*powers[ch[1]->s]+ch[1]->h1; h2=ch[1]->h2*powers[ch[0]->s+1]+v*powers[ch[0]->s]+ch[0]->h2; } void reverse(){ flip^=1; swap(ch[0],ch[1]); swap(h1,h2); } void pushdown(){ if(flip){ flip=0; ch[0]->reverse(); ch[1]->reverse(); } } }pool[MAXN]; void init_null(){ null=new Node(); null->s=0; } void rotate(Node*& o,int d){ Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } //k>=1 void splay(Node*& o,int k){ o->pushdown(); int d=o->cmp(k); if(d==1) k-=o->ch[0]->s+1; if(d!=-1){ Node* p=o->ch[d]; p->pushdown(); int d2=p->cmp(k); int k2=(d2==0?k:k-p->ch[0]->s-1); if(d2!=-1){ splay(p->ch[d2],k2); if(d2==d) rotate(o,d^1); else rotate(o->ch[d],d); } rotate(o,d^1); } } struct SplaySequence{ char* s; Node* root; // update dummy nodes //root: dummy min node // root->ch[1]: dummy max node // root->ch[1]->ch[0]: actual sequence void update_dummy(){ root->ch[1]->maintain(); root->maintain(); } //[L,R) Node* build(int L,int R){ int mid=L+(R-L)/2; Node* o=new Node(s[mid]); if(L<mid) o->ch[0]=build(L,mid); if(mid+1<R) o->ch[1]=build(mid+1,R); o->maintain(); return o; } Node* build(char* s){ this->s=s; root=new Node('['); root->ch[1]=new Node(']'); root->ch[1]->ch[0]=build(0,strlen(s)); update_dummy(); return root; } //[L,R) L>=1 Node*& range(int L,int R){ splay(root,L); splay(root->ch[1],R-L+1); return root->ch[1]->ch[0]; } }ss; int N,M; char str[MAXN]; int main(){ freopen("in.txt","r",stdin); powers[0]=1; for(int i=1;i<MAXN;i++) powers[i]=powers[i-1]*3137; while(scanf("%d%d%s",&N,&M,str)!=EOF){ pit=pool; init_null(); ss.build(str); int op,x,y; while(M--){ scanf("%d%d",&op,&x); if(op==1){ scanf("%d",&y); ss.range(x+1,x+1)=new Node(y+'0'); ss.update_dummy(); } else if(op==2){ ss.range(x,x+1)=null; ss.update_dummy(); } else if(op==3){ scanf("%d",&y); ss.range(x,y+1)->reverse(); ss.update_dummy(); } else{ scanf("%d",&y); //[L,R) int L=0,R=ss.root->s-y; while(L+1<R){ int mid=L+(R-L)/2; unsigned h1=ss.range(x,x+mid)->h1; if(h1==ss.range(y,y+mid)->h1) L=mid; else R=mid; } printf("%d\n",L); } } } return 0; }
相关文章推荐
- UVa 11996 Jewel Magic 伸展树
- UVA 11996 Jewel Magic(伸展树)
- 基本算法连载(2)-Splay Tree,中文叫伸展树,或者分裂树
- 伸展树Splay & 平衡树SBT(上)-----转载于BOB HAN
- 数据结构之伸展树
- 伸展树的学习(二):源代码分析
- [zz]伸展树
- Data Structures (Weiss) Chapter 12: Splay Tree 伸展树
- hdu 2871 Memory Control 伸展树区间合并
- POJ A Simple Problem with Integers (Splay 伸展树 入门)
- 伸展树(三)之 Java的实现
- 纸上谈兵:伸展树(splay tree)
- 【UVA】11922 Permutation Transformer 伸展树
- HDU 1890——Robotic Sort(伸展树)
- 伸展树
- HNOI2002营业额统计 (伸展树---模板题)
- 伸展树的构建和最基本的插入与查询
- 伸展树
- 数据结构实现之Splay伸展树
- HDU 3487(伸展树模板)