UVA 11996 Jewel Magic —— splay、序列的分裂与合并、LCP的哈希算法

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <vector>
  6
  7 using namespace std;
  8
  9 typedef unsigned long long ull;
 10 const int x = 123;
 11 const int maxn = 4e5 + 10;
 12
 13 ull xp[maxn];
 14 int n, m;
 15 struct Node {
 16     Node* ch[2];
 17     int r, v, s;
 18     int val;
 19     ull Hush[2];
 20     int flip;
 21     Node(int v1, int v2): v(v1), val(v2) {
 22         r = rand();
 23         s = 1;
 24         ch[0] = ch[1] = NULL;
 25         flip = 0;
 26         Hush[0] = Hush[1] = val;
 27     }
 28     bool cmp(const int &x) const {
 29         if(x == v) return -1;
 30         return x < v ? 0 : 1;
 31     }
 32     void maintain() {
 33         s = 1;
 34         Hush[0] = Hush[1] = val;
 35         if(ch[0] != NULL) s += ch[0]->s, Hush[0] = ch[0]->Hush[ch[0]->flip] + val*xp[ch[0]->s];
 36         if(ch[1] != NULL) Hush[0] += (ch[1]->Hush[ch[1]->flip])*xp[s], s += ch[1]->s;
 37         int s2 = 1;
 38         if(ch[1] != NULL) s2 += ch[1]->s, Hush[1] = ch[1]->Hush[(ch[1]->flip)^1] + val*xp[ch[1]->s];
 39         if(ch[0] != NULL) Hush[1] += (ch[0]->Hush[(ch[0]->flip)^1])*xp[s2];
 40     }
 41     void pushdown() {
 42         if(flip) {
 43             flip = 0;
 44             swap(ch[0], ch[1]);
 45             if(ch[0] != NULL) ch[0]->flip = !ch[0]->flip;
 46             if(ch[1] != NULL) ch[1]->flip = !ch[1]->flip;
 47         }
 48     }
 49 };
 50
 51 void rotate(Node* &o, int d) {
 52     Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
 53     o->maintain(); k->maintain(); o = k;
 54 }
 55
 56 void insert(Node* &o, int x, int val) {
 57     if(o == NULL) o = new Node(x, val);
 58     else {
 59         int d = o->cmp(x);
 60         insert(o->ch[d], x, val);
 61         if(o->ch[d]->r > o->r) rotate(o, d^1);
 62     }
 63     o->maintain();
 64 }
 65 void splay(Node* &o, int k) {
 66     o->pushdown();
 67     int s = o->ch[0] == NULL ? 0 : o->ch[0]->s;
 68     int d = k <= s ? 0 : (k == s+1? -1 : 1);
 69     if(d == 1) k -= s+1;
 70     if(d != -1) {
 71         splay(o->ch[d], k);
 72         rotate(o, d^1);
 73     }
 74 }
 75
 76 Node * merge(Node* left, Node* right) {
 77     splay(left, left->s);
 78     left->ch[1] = right;
 79     left->maintain();
 80     return left;
 81 }
 82 void split(Node* o, int k , Node* &left, Node* &right) {
 83     splay(o, k);
 84     left = o;
 85     right = o->ch[1];
 86     o->ch[1] = NULL;
 87     left->maintain();
 88 }
 89
 90 void oper1(Node* &o, int p, int c) {
 91     Node* left, *right;
 92     Node* node = new Node(p+1, c);
 93     split(o, p+1, left, right);
 94     o = merge(merge(left, node), right);
 95 }
 96 void oper2(Node* &o, int p) {
 97     Node* left, *mid, *right;
 98     split(o, p, left, mid);
 99     split(mid, 1, mid, right);
100     o = merge(left, right);
101 }
102 void oper3(Node* &o, int p1, int p2) {
103     Node *left, *mid, *right;
104     split(o, p1, left, mid);
105     split(mid, p2-p1+1, mid, right);
106     mid->flip ^= 1;
107     o = merge(merge(left, mid), right);
108 }
109 ull Hush_val(Node* &o, int p, int L) {
110     Node *left, *mid, *right;
111     split(o, p, left, mid);
112     split(mid, L, mid, right);
113     ull ans =  mid->Hush[mid->flip];
114     o = merge(merge(left, mid), right);
115     return ans;
116 }
117 int oper4(Node* &o, int p1, int p2) {
118     int L = 0, R = min(n-p1+1, n-p2+1);
119     while(L < R) {
120         int M = R - (R-L)/2;
121         int l1 = Hush_val(o, p1, M), l2 =  Hush_val(o, p2, M);
122         if(l1 == l2) L = M;
123         else R = M-1;
124     }
125     return L;
126 }
127 char s[maxn];
128 int main() {
129     xp[0] = 1;
130     for(int i = 1; i < maxn; i++) xp[i] = xp[i-1]*x;
131     while(scanf("%d%d", &n, &m) == 2) {
132         scanf("%s", s);
133         Node* root = new Node(0, 0);
134         for(int i = 0; i < n; i++) {
135             int c = s[i] - ‘0‘;
136             insert(root, i+1, c);
137         }
138         for(int i = 0; i < m; i++) {
139             int id, p1, p2;
140             scanf("%d", &id);
141             if(id == 1) {
142                 scanf("%d%d", &p1, &p2);
143                 oper1(root, p1, p2);
144                 n++;
145             }
146             if(id == 2) {
147                 scanf("%d", &p1);
148                 oper2(root, p1);
149                 n--;
150             }
151             if(id == 3) {
152                 scanf("%d%d", &p1, &p2);
153                 oper3(root, p1, p2);
154             }
155             if(id == 4) {
156                 scanf("%d%d", &p1, &p2);
157                 int ans = oper4(root, p1, p2);
158                 printf("%d\n", ans);
159             }
160         }
161     }
162     return 0;
163 }
时间: 2024-08-10 02:01:56

UVA 11996 Jewel Magic —— splay、序列的分裂与合并、LCP的哈希算法的相关文章

Uva 11996 Jewel Magic (Splay)

Jewel Magic Description 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 i

UVa 11996 Jewel Magic (splay + Hash + 二分)

题意:给定一个长度为n的01串,你的任务是依次执行如表所示的m条指令: 1 p c 在第p个字符后插入字符,p = 0表示在整个字符串之前插入2 p 删除第p个字符,后面的字符往前移3 p1 p2反转第p1到第p2个字符4 p1 p2输出从p1开始和p2开始的两个后缀的LCP. 析:对于前三个操作,splay 很容易就可以解决,但是对于最后一个操作,却不是那么容易,因为这是动态的,所以我们也要维护一个可以动态的,这就可以用Hash来解决,由于要翻转,所以要维护两个,一个正向的,一个反向的.在操作

uva 1608 不无聊的序列(附带常用算法设计和优化策略总结)

uva 1608 不无聊的序列(附带常用算法设计和优化策略总结) 紫书上有这样一道题: 如果一个序列的任意连续子序列中都至少有一个只出现一次的元素,则称这个序列时不无聊的.输入一个n个元素的序列,判断它是不是无聊的序列.n<=200000. 首先,在整个序列中找到只出现一次的元素ai.如果不能找到,那它就是无聊的.不然,就可以退出当前循环,递归判断[1, i-1]和[i+1, n]是不是无聊的序列.然而怎么找ai很重要.如果从一头开始找,那么最差情况下的时间复杂度就是O(n^2)的.而如果从两头

Opencv图像识别从零到精通(25)------区域分裂与合并

区域分割一般认为有漫水填充,区域分裂与合并,分水岭,这篇是中间的区域分裂和合并. 区域分裂合并算法的基本思想是先确定一个分裂合并的准则,即区域特征一致性的测度,当图像中某个区域的特征不一致时就将该区域分裂成4 个相等的子区域,当相邻的子区域满足一致性特征时则将它们合成一个大区域,直至所有区域不再满足分裂合并的条件为止.  当分裂到不能再分的情况时,分裂结束,然后它将查找相邻区域有没有相似的特征,如果有就将相似区域进行合并,最后达到分割的作用.  在一定程度上区域生长和区域分裂合并算法有异曲同工之

python kayb算法之从一组序列当中获取一组与目标值最接近的算法

python  kayb算法之从一组序列当中获取一组与目标值最接近的算法 思想:1.考虑所有序列当中的所有元素相遇的情况进行迭代2.在迭代过程当中维护一个与目标数值的最小差值3.在迭代完之后剩余的那一项 即为与目标值最接近的元素序列注意: 1.如果总和大于目标数需要判断此时大于目标数的和与前一个值总和哪个差值最小 2.考虑初始序列元素与目标值的最小差值 3.考虑序列当中所有元素的总和比目标值小问题: 1.是否有最小可以接受的范围 可以大大提高时间 1 # -*- coding:utf-8 -*-

UVA 11922 Splay区间翻转+分裂+合并

- Permutation Transformer Time Limit:2000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 11922 Appoint description:  System Crawler  (2014-11-30) Description  Permutation Transformer  Write a program to transform th

模板——伸展树 splay 实现快速分裂合并的序列

伸展操作:将treap中特定的结点旋转到根 //将序列中从左数第k个元素伸展到根,注意结点键值保存的是原序列id void splay(Node* &o, int k) { int s = o->ch[0] == NULL ? 0 : o->ch[0]->s; int d = k <= s ? 0 : (k == s+1 ? -1 : 1); if(d == 1) k -= s+1; if(d != -1) { splay(o->ch[d], k); rotate(o

UVA 11922 Permutation Transformer —— splay伸展树

题意:根据m条指令改变排列1 2 3 4 - n ,每条指令(a, b)表示取出第a~b个元素,反转后添加到排列尾部 分析:用一个可分裂合并的序列来表示整个序列,截取一段可以用两次分裂一次合并实现,粘贴到末尾可以用一次合并实现. 翻转可以采用在每个结点上做标记的方法,flip = 1意味着将这棵子树翻转,可以类似线段树用一个pushdown()实现标记向下传递. 可以发现当前排列就是伸展树的中序遍历序列.中序遍历打印结果即可. 注意代码中设置了虚拟首结点0的技巧. 代码如下: 1 #includ

HDU1890 Robotic Sort[splay 序列]

Robotic Sort Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3913    Accepted Submission(s): 1717 Problem Description Somewhere deep in the Czech Technical University buildings, there are labora