【bzoj1014】: [JSOI2008]火星人prefix 平衡树-字符串-hash-二分

【bzoj1014】: [JSOI2008]火星人

用平衡树维护字符串的hash

然后询问的时候二分一下就好了

  1 /* http://www.cnblogs.com/karl07/ */
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cmath>
  6 #include <algorithm>
  7 using namespace std;
  8 #define ull unsigned long long
  9
 10 const int N=1000005;
 11 const int P=131;
 12 struct tre{
 13     int key,sz,t;
 14     ull hash;
 15     tre *ls,*rs;
 16 }t[N*3],*NEW=t,*null=t,*root,*r1,*r2,*r3;
 17 ull base[N];
 18 char s[N];
 19 int n;
 20
 21 inline tre *new1(int x){
 22     NEW++;
 23     NEW->t=x;
 24     NEW->key=rand();
 25     NEW->sz=1;
 26     NEW->hash=x;
 27     NEW->ls=NEW->rs=null;
 28     return NEW;
 29 }
 30
 31 inline void update(tre *p){
 32     p->sz=p->ls->sz+1+p->rs->sz;
 33     p->hash=p->ls->hash*base[p->rs->sz+1]+p->t*base[p->rs->sz]+p->rs->hash;
 34 }
 35
 36 void merge(tre *&p,tre *x,tre *y){
 37     if (x==null) { p=y; return; }
 38     if (y==null) { p=x; return; }
 39     if (x->key>y->key){
 40         p=x;
 41         merge(p->rs,p->rs,y);
 42     }else{
 43         p=y;
 44         merge(p->ls,x,p->ls);
 45     }
 46     update(p);
 47 }
 48
 49 void split(tre *p,tre *&x,tre *&y,int k){
 50     if (k==0) { x=null,y=p; return; }
 51     if (k==p->sz) { y=null,x=p; return; }
 52     if (k>=p->ls->sz+1){
 53         x=p;
 54         split(p->rs,p->rs,y,k-p->ls->sz-1);
 55     }else{
 56         y=p;
 57         split(p->ls,x,p->ls,k);
 58     }
 59     update(p);
 60 }
 61
 62 void HASH(){
 63     null->ls=null->rs=null;
 64     null->hash=0;
 65     null->sz=null->t=0;
 66     null->key=-1;
 67     root=null;
 68     base[0]=1;
 69     for (int i=1;i<N;i++) base[i]=base[i-1]*P;
 70 }
 71
 72 inline ull Q(tre *p,int l,int x){
 73     ull ans;
 74     split(root,r1,r2,l-1);
 75     split(r2,r2,r3,x);
 76     ans=r2->hash;
 77     merge(r2,r2,r3);
 78     merge(root,r1,r2);
 79     return ans;
 80 }
 81
 82 inline void R(int l,int x){
 83     split(root,r1,r2,l-1);
 84     split(r2,r2,r3,1);
 85     merge(r1,r1,new1(x));
 86     merge(root,r1,r3);
 87 }
 88
 89 inline void I(int l,int x){
 90     split(root,r1,r2,l);
 91     merge(r1,r1,new1(x));
 92     merge(root,r1,r2);
 93 }
 94
 95 inline int query(int x,int y){
 96     if (x>y) swap(x,y);
 97     int l=0,r=root->sz-y+1,ans=0;
 98     while (l<=r){
 99         int mid=(l+r)/2;
100         ull a1=Q(root,x,mid),a2=Q(root,y,mid);
101         if (a1==a2){
102             ans=mid;
103             l=mid+1;
104         }else{
105             r=mid-1;
106         }
107     }
108     return ans;
109 }
110
111 int main(){
112     HASH();
113     scanf("%s",s);
114     scanf("%d",&n);
115     for (int i=0,l=strlen(s);i<=l-1;i++){
116         merge(root,root,new1(s[i]));
117     }
118     for (int i=1,x,y;i<=n;i++){
119         char ss[10],s1[10];
120         scanf("%s",ss);
121         if (ss[0]==‘Q‘) { scanf("%d%d",&x,&y); printf("%d\n",query(x,y)); }
122         if (ss[0]==‘R‘) { scanf("%d%s",&x,s1); R(x,s1[0]);}
123         if (ss[0]==‘I‘) { scanf("%d%s",&x,s1); I(x,s1[0]);}
124     }
125     return 0;
126 }

并不会splay。。只会非旋转treap。。10s正好卡过去。。药丸

时间: 2024-10-21 09:18:40

【bzoj1014】: [JSOI2008]火星人prefix 平衡树-字符串-hash-二分的相关文章

bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)

题目大意:一个字符串三个操作:①求两个后缀的LCP②插入一个字符③修改一个字符. 前几天刚学了hash+二分求lcp,就看到这题. 原来splay还能这么用?!原来splay模板这么好写?我以前写的splay是假的吧woc splay每个节点代表一个字符,并维护这个子树代表一个子串的哈希值.因为splay旋转不破坏树结构,所以不论怎么旋转这棵splay树都能代表这个字符串. 预处理处理少了调了半天呜呜呜 赶紧跑去更新自己的splay模板 #include<iostream> #include&

【BZOJ】1014: [JSOI2008]火星人prefix(splay+hash+二分+lcp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1014 被sb错调哭了QAQ...insert那里..插入到第x个后边...我......写成了第x个前面..........还调了!好!久! QAQ 本题神lcp做法....表示只会sa的height的离线.......这种在线的我就QAQ做个忧伤的表情... 然后膜拜了题解....好神..splay维护区间...hash+二分维护lcp....QAQ似乎是白书上说的么... 但是这种有概率的题这

bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix

http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include<cstdio> #include<cstring> #include<iostream> #define L 100001 typedef unsigned long long ULL; using namespace std; char s[L+4]; int tot,root

[BZOJ1014][JSOI2008]火星人prefix splay+hash+二分

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1014 先考虑如果没有修改操作和插入操作,是一个静态的字符串,我们可以怎样快速求得题目中的LCQ. 两个字符串判等很容易想到hash.于是我们二分答案并二分判断,就可以在$log_n$时间内得到答案. 现在加上修改和插入操作,其实就是要动态维护子串也就是一段区间的hash值,这种问题很容易就想到用splay来维护. 每个节点记录此节点管辖下子树的hash值h,当前节点的h=左孩子的h+节点

BZOJ-1014 [JSOI2008]火星人prefix (Splay+二分+hash)

题解: 用splay维护添加修改操作,然后二分hash判断长度. 操作一:对于查询区间[l,r]的hash值,显然将l-1旋到根,将r+1旋到根的右儿子,此时所求区间就是根的右儿子的左儿子了. 操作二:将要修改的位置旋到根,然后直接改就可以了. 操作三:要在x后面添加一个字符,显然将x旋到根,x+1旋到根的右儿子,然后直接加在根的右儿子的左儿子上就可以了. 1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio&g

[BZOJ1014] [JSOI2008] 火星人prefix (splay &amp; 二分答案)

Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串,两个字串的公共前缀的长度.比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4,

bzoj1014 火星人prefix Splay 字符串Hash

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1014 题意:动态修改字符串,动态查询某两个后缀之间的$LCP$长度. 这题肯定一堆人刚开始:$woc$这题好水啊,后缀数据结构放肆撸啊…… 等看到后半段:$woc$这个修改怎么改啊…… 实际上这个东西跟后缀数据结构半毛钱关系没有……正确做法就是$Hash$……不停地插入字符,修改整棵子树的$Hash$值,然后就是动态的修改$Hash$值……转啊转……修改……转……然后就出来了…… 1 #in

bzoj1014: [JSOI2008]火星人prefix Hash+Splay

Splay维护Hash值,每次二分. #include<bits/stdc++.h> #define L(t) (t)->c[0] #define R(t) (t)->c[1] #define Z(t) (L(t)->s+1) #define N 100010 #define M (l+r>>1) typedef unsigned long long ull; ull a[N]; struct node{ int v,s; ull u; node* c[2]; n

[BZOJ1014][JSOI2008]火星人prefix

试题描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串,两个字串的公共前缀的长度.比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0