Jewel Magic UVA - 11996 || bzoj1014: [JSOI2008]火星人prefix

Jewel Magic UVA - 11996

这是一道用splay/非旋treap做的题(这里用的是非旋treap)

1/2/3是splay/非旋treap的常规操作。对于操作4,可以用哈希法求LCP。记hash(i,L)为子串[i,i+L-1](即第i个开始的L个)的hash值。记s[i]为序列第i位(编号从1开始),n为序列长度

如果通过某种方式做到能在O(logn)时间内取出一段子串的hash值,那么二分答案(即LCP长度x),可以在O(logn)时间内判一个x是否合法(如果hash(l,x)==hash(r,x)则认为[l,l+x-1]和[r,r+x-1]是相同的,合法,否则不合法),可以做到在O(log^2n)内完成一个操作4。当然,hash判字符串是否相同正确性可能受影响,因此可以多计算一些hash,当他们都相同时才认为字符串相同,可以将错误率降到足够小。

如何维护一段子串的hash值?首先定义x为任意整数,定义$hash(i,L)=s[i+L-1]*x^{L-1}+s[i+L-2]*x^{L-2}+...+s[i+1]*x+s[i]$

(这里及之后都省略了取模)

(简单记法:左边乘的次数小)

(另一种记法:另一种求法的伪代码表示:ans=0;for(j=i+L-1;j>=i;j--)  ans=ans*x+s[j];)

可以发现:如果已知hash(i,p)和hash(i+p,q)(即已知[i,i+p-1]和[i+p,i+p+q-1]的hash值),要求hash(i,p+q)(就是这两段合起来的hash值),那么:

令j=i+p,那么$hash(i,p+q)$

$=s[j+q-1]*x^{p+q-1}+s[j+q-2]*x^{p+q-2}+...+s[j]*x^p+s[i+p-1]*x^{p-1}+...+s[i]*x^0$

所以$hash(i,p+q)=hash(j,q)*x^p+hash(i,p)=hash(i,p)+hash(i+p,q)*x^p$

这样就得到了对于平衡树某个节点,根据子节点为根的子树的hash值与自身值求以自身为根的子树的hash值的方法(先将左子树和自身合起来,再将结果与右子树合起来)

当然,由于此题有一个翻转操作,对于一个节点要维护两个hash:正向序列hash和反向序列hash。翻转操作时顺便交换一下两个的值。

附:这道题没有卡hash,单hash就能过,

附:听说操作4有O(logn)的方法?待解决

错误记录:

1.141行误用build函数(build是用的左闭右闭区间),输入了(a+1,a+n+1)。(然而不知道为什么虽然过不了udebug的数据然而把题目A掉了)

2.没注意在字符前还是字符后插入

*3.posib函数写错:没有考虑要计算hash值的串超出长度范围的情况(就是第二个"&&"之前的部分)。错了不止一次

4.可能出现的错误:如果hash不用ull自然溢出,自己取模,那么要考虑爆int、爆longlong、负数等等

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 inline int rand1()
  5 {
  6     static int x=471;
  7     return x=(48271LL*x+1)%2147483647;
  8 }
  9 unsigned long long powx[400010];
 10 struct Node
 11 {
 12     Node(){}
 13     Node* ch[2];
 14     int r;
 15     bool flip;
 16     int v;
 17     unsigned long long h,rh;
 18     int size;
 19     void upd()
 20     {
 21         if(ch[0])   ch[0]->pd();
 22         if(ch[1])   ch[1]->pd();
 23         size=1+(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0);
 24         h=(ch[0]?ch[0]->h:0)+v*powx[ch[0]?ch[0]->size:0]+(ch[1]?ch[1]->h:0)*powx[(ch[0]?ch[0]->size:0)+1];
 25         rh=(ch[1]?ch[1]->rh:0)+v*powx[ch[1]?ch[1]->size:0]+(ch[0]?ch[0]->rh:0)*powx[(ch[1]?ch[1]->size:0)+1];
 26     }
 27     void pd()
 28     {
 29         if(flip)
 30         {
 31             swap(ch[0],ch[1]);
 32             swap(h,rh);
 33             if(ch[0])   (ch[0]->flip)^=1;
 34             if(ch[1])   (ch[1]->flip)^=1;
 35             flip=0;
 36         }
 37     }
 38 }nodes[400010];
 39 Node* root;int mem;
 40 Node* getnode(){return nodes+(mem++);}
 41 Node* merge(Node* a,Node* b)
 42 {
 43     if(a==NULL)    return b;
 44     if(b==NULL)    return a;
 45     if(a->r < b->r)
 46     {
 47         a->pd();a->ch[1]=merge(a->ch[1],b);a->upd();
 48         return a;
 49     }
 50     else
 51     {
 52         b->pd();b->ch[0]=merge(a,b->ch[0]);b->upd();
 53         return b;
 54     }
 55 }
 56 typedef pair<Node*,Node*> P;
 57 P split(Node* a,int n)
 58 {
 59     if(a==NULL)    return P(NULL,NULL);
 60     P y;
 61     a->pd();int s=a->ch[0] ? a->ch[0]->size : 0;
 62     if(s>=n)
 63     {
 64         y=split(a->ch[0],n);
 65         a->ch[0]=y.second;a->upd();
 66         y.second=a;
 67     }
 68     else
 69     {
 70         y=split(a->ch[1],n-s-1);
 71         a->ch[1]=y.first;a->upd();
 72         y.first=a;
 73     }
 74     return y;
 75 }
 76 inline void insert(int k,int x)
 77 {
 78     Node* t=getnode();
 79     t->ch[0]=t->ch[1]=NULL;t->r=rand1();t->v=x;t->flip=0;t->upd();
 80     P y=split(root,k-1);
 81     root=merge(merge(y.first,t),y.second);
 82 }
 83 inline void erase(int k)
 84 {
 85     P y=split(root,k-1);
 86     P y2=split(y.second,1);
 87     root=merge(y.first,y2.second);
 88 }
 89 inline void reverse(int l,int r)
 90 {
 91     if(l>r) swap(l,r);
 92     P y=split(root,l-1);
 93     P y2=split(y.second,r-l+1);
 94     y2.first->flip^=1;
 95     root=merge(merge(y.first,y2.first),y2.second);
 96 }
 97 inline int size()
 98 {
 99     return root ? root->size : 0;
100 }
101 inline unsigned long long geth(int l,int r)
102 {
103     if(l>r)  return 0;
104     P y=split(root,l-1);
105     P y2=split(y.second,r-l+1);
106     unsigned long long ans=y2.first ? y2.first->h : 0;
107     root=merge(merge(y.first,y2.first),y2.second);
108     return ans;
109 }
110 Node* build(int *l,int *r)
111 {
112     if(l>r) return NULL;
113     if(l==r)
114     {
115         Node* t=getnode();
116         t->ch[0]=t->ch[1]=NULL;t->r=rand1();t->v=*l;t->flip=0;t->upd();
117         return t;
118     }
119     else
120     {
121         int* mid=l+(r-l)/2;
122         return merge(build(l,mid),build(mid+1,r));
123     }
124 }
125 int n,m,q;
126 int a[200010];
127 const int X=127;
128 int l,r;
129 inline bool posib(int x)
130 {
131     return (l+x-1<=size())&&(r+x-1<=size())&&(geth(l,l+x-1)==geth(r,r+x-1));
132 }
133 int main()
134 {
135     register int i;
136     int lx,rx,k,x,mid,tmp;
137     powx[0]=1;
138     for(i=1;i<=400000;i++)  powx[i]=powx[i-1]*X;
139     scanf("%d%d",&n,&q);
140     for(i=1;i<=n;i++)    scanf("%1d",&a[i]);
141     root=build(a+1,a+n);
142     while(q--)
143     {
144         scanf("%d",&tmp);
145         if(tmp==1)
146         {
147             scanf("%d%d",&k,&x);
148             insert(k+1,x);
149         }
150         else if(tmp==2)
151         {
152             scanf("%d",&k);
153             erase(k);
154         }
155         else if(tmp==3)
156         {
157             scanf("%d%d",&l,&r);
158             reverse(l,r);
159         }
160         else if(tmp==4)
161         {
162             scanf("%d%d",&l,&r);
163             lx=0;rx=size()+1;
164             while(rx-lx>1)
165             {
166                 mid=(lx+rx)>>1;
167                 if(posib(mid))  lx=mid;
168                 else    rx=mid;
169             }
170             printf("%d\n",lx);
171         }
172     }
173     return 0;
174 }

https://www.lydsy.com/JudgeOnline/problem.php?id=1014

https://www.luogu.org/problemnew/show/P4036

贴一下常数超大的代码

做法类似

  1 #pragma GCC optimize("Ofast")
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 inline int rand1()
  7 {
  8     static int x=471;
  9     return x=(48271LL*x+1)%2147483647;
 10 }
 11 unsigned long long powx[100010];
 12 struct Node
 13 {
 14     Node(){}
 15     Node* ch[2];
 16     int r;
 17     int v;
 18     unsigned long long h;
 19     int size;
 20     void upd()
 21     {
 22         size=1+(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0);
 23         h=(ch[0]?ch[0]->h:0)+v*powx[ch[0]?ch[0]->size:0]+(ch[1]?ch[1]->h:0)*powx[(ch[0]?ch[0]->size:0)+1];
 24     }
 25 }nodes[250010];
 26 Node* root;int mem;
 27 Node* getnode(){return nodes+(mem++);}
 28 Node* merge(Node* a,Node* b)
 29 {
 30     if(a==NULL)    return b;
 31     if(b==NULL)    return a;
 32     if(a->r < b->r)
 33     {
 34         a->ch[1]=merge(a->ch[1],b);a->upd();
 35         return a;
 36     }
 37     else
 38     {
 39         b->ch[0]=merge(a,b->ch[0]);b->upd();
 40         return b;
 41     }
 42 }
 43 typedef pair<Node*,Node*> P;
 44 P split(Node* a,int n)
 45 {
 46     if(a==NULL)    return P(NULL,NULL);
 47     P y;
 48     int s=a->ch[0] ? a->ch[0]->size : 0;
 49     if(s>=n)
 50     {
 51         y=split(a->ch[0],n);
 52         a->ch[0]=y.second;a->upd();
 53         y.second=a;
 54     }
 55     else
 56     {
 57         y=split(a->ch[1],n-s-1);
 58         a->ch[1]=y.first;a->upd();
 59         y.first=a;
 60     }
 61     return y;
 62 }
 63 inline void insert(int k,int x)
 64 {
 65     Node* t=getnode();
 66     t->r=rand1();t->v=x;t->upd();
 67     P y=split(root,k-1);
 68     root=merge(merge(y.first,t),y.second);
 69 }
 70 inline void erase(int k)
 71 {
 72     P y=split(root,k-1);
 73     P y2=split(y.second,1);
 74     root=merge(y.first,y2.second);
 75 }
 76  
 77 inline int size()
 78 {
 79     return root ? root->size : 0;
 80 }
 81 inline unsigned long long geth(int l,int r)
 82 {
 83     if(l>r)  return 0;
 84     P y=split(root,l-1);
 85     P y2=split(y.second,r-l+1);
 86     unsigned long long ans=y2.first ? y2.first->h : 0;
 87     root=merge(merge(y.first,y2.first),y2.second);
 88     return ans;
 89 }
 90 Node* build(char *l,char *r)
 91 {
 92     if(l>r) return NULL;
 93     if(l==r)
 94     {
 95         Node* t=getnode();
 96         t->r=rand1();t->v=(int)(*l);t->upd();
 97         return t;
 98     }
 99     else
100     {
101         char* mid=l+(r-l)/2;
102         return merge(build(l,mid),build(mid+1,r));
103     }
104 }
105 int n,m,q;
106 char a[100010];
107 const int X=127;
108 int l,r;
109 char tmp;
110 inline bool posib(int x)
111 {
112     return (l+x-1<=size())&&(r+x-1<=size())&&(geth(l,l+x-1)==geth(r,r+x-1));
113 }
114 int main()
115 {
116     register int i;
117     int lx,rx,k,mid;
118     powx[0]=1;
119     for(i=1;i<=100000;i++)  powx[i]=powx[i-1]*X;
120     scanf("%s",a+1);n=strlen(a+1);
121     root=build(a+1,a+n);
122     scanf("%d",&q);
123     while(q--)
124     {
125         tmp=getchar();while(tmp<'A'||tmp>'Z') tmp=getchar();
126         if(tmp=='I')
127         {
128             scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z')  tmp=getchar();
129             insert(k+1,(int)tmp);
130         }
131         else if(tmp=='R')
132         {
133             scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z')  tmp=getchar();
134             erase(k);insert(k,(int)tmp);
135         }
136         else if(tmp=='Q')
137         {
138             scanf("%d%d",&l,&r);
139             lx=0;rx=size()+1;
140             while(rx-lx>1)
141             {
142                 mid=(lx+rx)>>1;
143                 if(posib(mid))  lx=mid;
144                 else    rx=mid;
145             }
146             printf("%d\n",lx);
147         }
148     }
149     return 0;
150 }

 

posted @ 2018-02-27 20:47  hehe_54321  阅读(220)  评论(0编辑  收藏  举报
AmazingCounters.com