您的位置:首页 > 其它

UVa 11996 Jewel Magic 伸展树

2014-02-27 18:58 309 查看
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的01串,你的任务是依次执行如表所示的m条指令:
1 p c 在第p个字符后插入字符,p = 0表示在整个字符串之前插入
2 p   删除第p个字符,后面的字符往前移
3 p1 p2反转第p1到第p2个字符
4 p1 p2输出从p1开始和p2开始的两个后缀的LCP。
有空再DEBUG。。。看得眼都花了、、、
/*

*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 200080
#define inf 0x3f3f3f3f
#define Key_value ch[ch[root][1]][0]
char str[maxn];
unsigned long long mi3[maxn];

struct SplayTree
{
int pre[maxn],ch[maxn][2],size[maxn],flip[maxn],root,cnt,len;
unsigned long long Hash1[maxn],Hash2[maxn],mul[maxn],div[maxn];
void debug()
{
printf("根结点是:%d\n",root);
Treaval(root);
}

void Treaval(int r)
{
if(!r)	return;
Treaval(ch[r][0]);
printf("结点: %d 左儿子:%d 右儿子:%d 哈希值:%lld 反哈希值:%lld Size:%d 父结点:%d\n",r,ch[r][0],ch[r][1],Hash1[r],Hash2[r],size[r],pre[r]);
Treaval(ch[r][1]);
}

void init(int n)
{
cnt = root = 0;
len = n;
ch[0][0] = ch[0][1] = pre[0] = flip[0] = size[0] = Hash1[0] = Hash2[0] = 0;
mul[0] = div[0] = 1;
NewNode(root,0,0,0);
NewNode(ch[root][1],0,root,0);
PushUp(root);
BuildTree(Key_value,1,n,ch[root][1]);
PushUp(ch[root][1]);
PushUp(root);
//debug();建树没建错。。
}

void NewNode(int & r,int k,int father,int num)//k表示这是第几位,num则是0或1.
{
r = ++cnt;
ch[r][0] = ch[r][1] = 0;
pre[r] = father;
size[r] = mul[r] = div[r] = 1;
flip[r] = 0;
Hash1[r] = num * mi3[k];
Hash2[r] = (num ^ 1) * mi3[k];
}///建树没错,这里新建结点也不会出错

void PushUp(int x)
{
int l = ch[x][0],r = ch[x][1];
size[x] = size[l] + size[r] + 1;
Hash1[x] = Hash1[l] + Hash1[r] + Hash1[x]*mul[x]/div[x];
Hash2[x] = Hash2[r] + Hash2[l] + Hash2[x]*mul[x]/div[x];
}

void Update_Rev(int x)
{
if(!x)	return;
swap(ch[x][0],ch[x][1]);
flip[x] ^= 1;
unsigned long long k = Hash1[x];
Hash1[x] = Hash2[x];
Hash2[x] = k;
}

void Update_Mul(int x,int Mul)
{
if(!x)	return;
Hash1[x] *= Mul;
Hash2[x] *= Mul;
mul[x] *= Mul;
}

void Update_Div(int x,int Div)
{
if(!x)	return;
Hash1[x] /= Div;
Hash2[x] /= Div;
div[x] *= Div;
}////三个Update函数都不会错

void PushDown(int x)
{
if(flip[x])
{
Update_Rev(ch[x][0]);
Update_Rev(ch[x][1]);
flip[x] = 0;
}
if(mul[x] != 1)
{
Update_Mul(ch[x][0],mul[x]);
Update_Mul(ch[x][1],mul[x]);
mul[x] = 1;
}
if(div[x] != 1)
{
Update_Div(ch[x][0],div[x]);
Update_Div(ch[x][1],div[x]);
div[x] = 1;
}
}/////这里也不会错了

void BuildTree(int & r,int L,int R,int father)
{
if(L > R)	return;
int mid = (L + R) >> 1;
NewNode(r,mid,father,str[mid-1] - '0');
BuildTree(ch[r][0],L,mid-1,r);
BuildTree(ch[r][1],mid+1,R,r);
PushUp(r);
}///

void Rotate(int x,int kind)
{
int y = pre[x];
PushDown(y);
PushDown(x);
ch[y][!kind] = ch[x][kind];
pre[ch[x][kind]] = y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1]==y] = x;
pre[x] = pre[y];
ch[x][kind] = y;
pre[y] = x;
PushUp(y);
}

void Splay(int r,int goal)
{
PushDown(r);
while(pre[r] != goal)
{
int y = pre[r],z = pre[y];
//PushDown(z);	PushDown(y);	PushDown(r);
if(pre[pre[r]] == goal)
Rotate(r,ch[pre[r]][0] == r);
else
{
int y = pre[r];
int kind = (ch[pre[y]][0] == y);
if(ch[y][kind] == r)
{
Rotate(r,!kind);
Rotate(r,kind);
}
else
{
Rotate(y,kind);
Rotate(r,kind);
}
}
}
PushUp(r);
if(goal == 0)	root = r;
}

int Get_Kth(int r,int k)
{
PushDown(r);
int t = size[ch[r][0]] + 1;
if(t == k)
return r;
if(t > k)
return Get_Kth(ch[r][0],k);
else return Get_Kth(ch[r][1],k-t);
}

int Get_Min(int r)
{
PushDown(r);
while(ch[r][0])
{
r = ch[r][0];
PushDown(r);
}
return r;
}///////不会错

int Get_Max(int r)
{
PushDown(r);
while(ch[r][1])
{
r = ch[r][1];
PushDown(r);
}
return r;
}///不会错

void insert(int k,int c)//操作1
{
int x = Get_Kth(root,k+1);
Splay(x,0);
int y = Get_Min(ch[root][1]);
Splay(y,root);
NewNode(Key_value,k+1,ch[root][1],c);
PushUp(ch[root][1]);
PushUp(root);
//接下来得懒惰标记
x = Get_Kth(root,k+2);
Splay(x,0);
y = Get_Max(root);
Splay(y,root);
Update_Mul(Key_value,3);
len++;
//debug();
}

void remove(int k)//操作2
{
int x = Get_Kth(root,k);
Splay(x,0);
int y = Get_Kth(root,k+2);
Splay(y,root);
//现在Key_value 就是要删除的那个结点了
Key_value = 0;
PushUp(ch[root][1]);
PushUp(root);
x = Get_Kth(root,k);
Splay(x,0);
y = Get_Max(root);
Splay(y,root);
Update_Div(Key_value,3);
len--;
}

void Reversal(int l,int r)//操作3
{
int x = Get_Kth(root,l);
Splay(x,0);
int y = Get_Kth(root,r+2);
Splay(y,root);
Update_Rev(Key_value);
}

int Lcp(int l,int r)//操作4,输出从l开始和r开始的两个后缀的LCP
{
debug();
int L = 0,R = len - r + 1;
int ans = 0;
while(L <= R)
{
int mid = (L + R) >> 1;
int x = Get_Kth(root,l);
Splay(x,0);
int y = Get_Kth(root,l+mid+2);
Splay(y,root);
unsigned long long k = Hash1[Key_value];
x = Get_Kth(root,r);
Splay(x,0);
y = Get_Kth(root,r+mid+2);
Splay(y,root);
if(k*mi3[r-l] == Hash1[Key_value])
{
ans = mid;
L = mid + 1;
}
else R = mid - 1;
}
return ans;
}

void solve(int m)
{
spt.init(strlen(str));
while(m--)
{
int ope,p1,p2;
scanf("%d",&ope);
if(ope == 1)
{
scanf("%d%d",&p1,&p2);
insert(p1,p2);
}
else if(ope == 2)
{
scanf("%d",&p1);
remove(p1);
}
else if(ope == 3)
{
scanf("%d%d",&p1,&p2);
Reversal(p1,p2);
}
else
{
scanf("%d%d",&p1,&p2);
printf("%d\n",Lcp(p1,p2));
}
}
}
}spt;

int main()
{
freopen("in.txt","r",stdin);
int n,m;
mi3[0] = 1;
for(int i = 1;i <= 200000;i++)
{
mi3[i] = 3*mi3[i-1];
}
while(scanf("%d%d",&n,&m)==2)
{
scanf("%s",str);
spt.solve(m);
}
return 0;
}
终于出样例了~~热泪盈眶!!华丽丽TLE了、、、一口血喷出来!!简直不能忍!!!先刷别的题,有灵感再来。。
 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 400080
#define inf 0x3f3f3f3f
#define Key_value ch[ch[root][1]][0]
char str[maxn];
unsigned long long mi[maxn];
#define mimi 3

struct SplayTree
{
int pre[maxn],ch[maxn][2],size[maxn],flip[maxn],root,cnt,len;
unsigned long long Hash1[maxn],Hash2[maxn],Hashme[maxn],mul[maxn],div[maxn];
void debug()
{
printf("结点是:%d\n",root);
Treaval(root);
}

void Treaval(int r)
{
if(!r)	return;
Treaval(ch[r][0]);
printf("结点: %d 左儿子:%d 右儿子:%d 树哈希值:%lld 树反反哈希值:%lld 单点哈希值: %lld    Size:%d 父结点:%d\n",r,ch[r][0],ch[r][1],Hash1[r],Hash2[r],Hashme[r],size[r],pre[r]);
Treaval(ch[r][1]);
}

void init(int n)
{
cnt = root = 0;
len = n;
ch[0][0] = ch[0][1] = pre[0] = flip[0] = size[0] = Hash1[0] = Hash2[0] = Hashme[0] = 0;
mul[0] = div[0] = 1;
NewNode(root,0,0,0);
NewNode(ch[root][1],0,root,0);
PushUp(root);
BuildTree(Key_value,1,n,ch[root][1]);
PushUp(ch[root][1]);
PushUp(root);
//debug();
}

void NewNode(int & r,int k,int father,int num)//k表示这是第几位,num则是0或1.
{
r = ++cnt;
ch[r][0] = ch[r][1] = 0;
pre[r] = father;
size[r] = mul[r] = div[r] = 1;
flip[r] = 0;
Hash1[r] = Hash2[r] = Hashme[r] = num * mi[k];
}

void PushUp(int x)
{
int l = ch[x][0],r = ch[x][1];
size[x] = size[l] + size[r] + 1;
Hash1[x] = Hash1[l] + Hash1[r] + Hashme[x];
Hash2[x] = Hash2[l] * mi[size[r]+1] + Hash2[r] / mi[size[l]+1] + (size[r] > size[l] ? Hashme[x] * mi[size[r]-size[l]] : Hashme[x] / mi[size[l]-size[r]]);
}

void Update_Rev(int x)
{
if(!x)	return;
flip[x] ^= 1;
if(size[ch[x][1]] > size[ch[x][0]])
Hashme[x] *= mi[size[ch[x][1]] - size[ch[x][0]]];
else Hashme[x] /= mi[size[ch[x][0]] - size[ch[x][1]]];
swap(ch[x][0],ch[x][1]);
unsigned long long k = Hash1[x];
Hash1[x] = Hash2[x];
Hash2[x] = k;
}

void Update_Mul(int x,int Mul)
{
if(!x)	return;
mul[x] *= Mul;
Hash1[x] *= Mul;
Hash2[x] *= Mul;
Hashme[x] *= Mul;
}

void Update_Div(int x,int Div)
{
if(!x)	return;
div[x] *= Div;
Hash1[x] /= Div;
Hash2[x] /= Div;
Hashme[x] /= Div;
}

void PushDown(int x)
{
if(flip[x])
{
Update_Rev(ch[x][0]);
Update_Rev(ch[x][1]);
flip[x] = 0;
}
if(mul[x] != 1)
{
if(mul[x] >= div[x])
{
div[x] = 1;
mul[x] /= div[x];
}
Update_Mul(ch[x][0],mul[x]);
Update_Mul(ch[x][1],mul[x]);
mul[x] = 1;
}
if(div[x] != 1)
{
Update_Div(ch[x][0],div[x]);
Update_Div(ch[x][1],div[x]);
div[x] = 1;
}
}

void BuildTree(int & r,int L,int R,int father)
{
if(L > R)	return;
int mid = (L + R) >> 1;
NewNode(r,mid,father,str[mid-1] - '0');
BuildTree(ch[r][0],L,mid-1,r);
BuildTree(ch[r][1],mid+1,R,r);
PushUp(r);
}

void Rotate(int x,int kind)
{
int y = pre[x];
PushDown(y);
PushDown(x);
ch[y][!kind] = ch[x][kind];
pre[ch[x][kind]] = y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1]==y] = x;
pre[x] = pre[y];
ch[x][kind] = y;
pre[y] = x;
PushUp(y);
}

void Splay(int r,int goal)
{
PushDown(r);
while(pre[r] != goal)
{
int y = pre[r],z = pre[y];
//PushDown(z);	PushDown(y);	PushDown(r);
if(pre[pre[r]] == goal)
Rotate(r,ch[pre[r]][0] == r);
else
{
int y = pre[r];
int kind = (ch[pre[y]][0] == y);
if(ch[y][kind] == r)
{
Rotate(r,!kind);
Rotate(r,kind);
}
else
{
Rotate(y,kind);
Rotate(r,kind);
}
}
}
PushUp(r);
if(goal == 0)	root = r;
}

int Get_Kth(int r,int k)
{
PushDown(r);
int t = size[ch[r][0]] + 1;
if(t == k)
return r;
if(t > k)
return Get_Kth(ch[r][0],k);
else return Get_Kth(ch[r][1],k-t);
}

int Get_Min(int r)
{
PushDown(r);
while(ch[r][0])
{
r = ch[r][0];
PushDown(r);
}
return r;
}

int Get_Max(int r)
{
PushDown(r);
while(ch[r][1])
{
r = ch[r][1];
PushDown(r);
}
return r;
}

void insert(int k,int c)//操作1
{
int x = Get_Kth(root,k+1);
Splay(x,0);
int y = Get_Min(ch[root][1]);
Splay(y,root);
NewNode(Key_value,k+1,ch[root][1],c);
PushUp(ch[root][1]);
PushUp(root);
//接下来得懒惰标记
x = Get_Kth(root,k+2);
Splay(x,0);
y = Get_Max(root);
Splay(y,root);
Update_Mul(Key_value,mimi);
len++;
}

void remove(int k)//操作2
{
int x = Get_Kth(root,k);
Splay(x,0);
int y = Get_Kth(root,k+2);
Splay(y,root);
//现在Key_value 就是要删除的那个结点了
pre[Key_value] = 0;
Key_value = 0;
PushUp(ch[root][1]);
PushUp(root);
x = Get_Kth(root,k);
Splay(x,0);
y = Get_Max(root);
Splay(y,root);
Update_Div(Key_value,mimi);
len--;
}

void Reversal(int l,int r)//操作3
{
int x = Get_Kth(root,l);
Splay(x,0);
int y = Get_Kth(root,r+2);
Splay(y,root);
Update_Rev(Key_value);
}

int Lcp(int l,int r)//操作4,输出从l开始和r开始的两个后缀的LCP
{
int L = 0,R = len - r + 1;
int ans = 0;
while(L <= R)
{
int mid = (L + R) >> 1;
int x = Get_Kth(root,l);
Splay(x,0);
int y = Get_Kth(root,l+mid+1);
Splay(y,root);
unsigned long long k = Hash1[Key_value];
x = Get_Kth(root,r);
Splay(x,0);
y = Get_Kth(root,r+mid+1);
Splay(y,root);
if(k*mi[r-l] == Hash1[Key_value])
{
ans = mid;
L = mid + 1;
}
else R = mid - 1;
}
return ans;
}

void solve(int m)
{
init(strlen(str));
while(m--)
{
int ope,p1,p2;
scanf("%d",&ope);
if(ope == 1)
{
scanf("%d%d",&p1,&p2);
insert(p1,p2);
}
else if(ope == 2)
{
scanf("%d",&p1);
remove(p1);
}
else if(ope == 3)
{
scanf("%d%d",&p1,&p2);
Reversal(p1,p2);
}
else
{
scanf("%d%d",&p1,&p2);
printf("%d\n",Lcp(p1,p2));
}
}
}
}spt;

int main()
{
//freopen("in.txt","r",stdin);
int n,m;
mi[0] = 1;
for(int i = 1;i <= 300000;i++)
{
mi[i] = mimi*mi[i-1];
}
while(scanf("%d%d",&n,&m)==2)
{
scanf("%s",str);
spt.solve(m);
}
return 0;
}
终于~~~AC、、、4秒多!!!!
Hash的方式我用的太挫了!用在该子树的位置来运用Hash、、、我原先的做法是整棵树中的位置。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define maxn 400080#define inf 0x3f3f3f3f#define Key_value ch[ch[root][1]][0]char str[maxn];unsigned long long mi[maxn];#define mimi 3struct SplayTree{int pre[maxn],ch[maxn][2],size[maxn],flip[maxn],root,cnt,len;unsigned long long Hash1[maxn],Hash2[maxn],key[maxn];void init(int n){cnt = root = 0;len = n;ch[0][0] = ch[0][1] = pre[0] = flip[0] = size[0] = Hash1[0] = Hash2[0] = 0;NewNode(root,0,0);NewNode(ch[root][1],root,0);PushUp(root);BuildTree(Key_value,1,n,ch[root][1]);PushUp(ch[root][1]);PushUp(root);}void NewNode(int & r,int father,int num)//num则是0或1.{r = ++cnt;ch[r][0] = ch[r][1] = 0;pre[r] = father;size[r] = 1;flip[r] = 0;key[r] = Hash1[r] = Hash2[r] = num;}void PushUp(int x){int l = ch[x][0],r = ch[x][1];size[x] = size[l] + size[r] + 1;Hash1[x] = Hash1[l] * mi[size[r]+1] + Hash1[r] + key[x]*mi[size[r]];Hash2[x] = Hash2[r] * mi[size[l]+1] + Hash2[l] + key[x]*mi[size[l]];}void Update_Rev(int x){if(!x)	return;flip[x] ^= 1;swap(ch[x][0],ch[x][1]);unsigned long long k = Hash1[x];Hash1[x] = Hash2[x];Hash2[x] = k;}void PushDown(int x){if(flip[x]){Update_Rev(ch[x][0]);Update_Rev(ch[x][1]);flip[x] = 0;}}void BuildTree(int & r,int L,int R,int father){if(L > R)	return;int mid = (L + R) >> 1;NewNode(r,father,str[mid-1] - '0');BuildTree(ch[r][0],L,mid-1,r);BuildTree(ch[r][1],mid+1,R,r);PushUp(r);}void Rotate(int x,int kind){int y = pre[x];PushDown(y);PushDown(x);ch[y][!kind] = ch[x][kind];pre[ch[x][kind]] = y;if(pre[y])ch[pre[y]][ch[pre[y]][1]==y] = x;pre[x] = pre[y];ch[x][kind] = y;pre[y] = x;PushUp(y);}void Splay(int r,int goal){PushDown(r);while(pre[r] != goal){int y = pre[r],z = pre[y];//PushDown(z);	PushDown(y);	PushDown(r);if(pre[pre[r]] == goal)Rotate(r,ch[pre[r]][0] == r);else{int y = pre[r];int kind = (ch[pre[y]][0] == y);if(ch[y][kind] == r){Rotate(r,!kind);Rotate(r,kind);}else{Rotate(y,kind);Rotate(r,kind);}}}PushUp(r);if(goal == 0)	root = r;}int Get_Kth(int r,int k){PushDown(r);int t = size[ch[r][0]] + 1;if(t == k)return r;if(t > k)return Get_Kth(ch[r][0],k);else return Get_Kth(ch[r][1],k-t);}int Get_Min(int r){PushDown(r);while(ch[r][0]){r = ch[r][0];PushDown(r);}return r;}int Get_Max(int r){PushDown(r);while(ch[r][1]){r = ch[r][1];PushDown(r);}return r;}void insert(int k,int c)//操作1{int x = Get_Kth(root,k+1);Splay(x,0);int y = Get_Min(ch[root][1]);Splay(y,root);NewNode(Key_value,ch[root][1],c);PushUp(ch[root][1]);PushUp(root);//Splay(Key_value,0);len++;}void remove(int k)//操作2{int x = Get_Kth(root,k);Splay(x,0);int y = Get_Kth(root,k+2);Splay(y,root);//现在Key_value 就是要删除的那个结点了pre[Key_value] = 0;Key_value = 0;PushUp(ch[root][1]);PushUp(root);//Splay(ch[root][1],0);len--;}void Reversal(int l,int r)//操作3{int x = Get_Kth(root,l);Splay(x,0);int y = Get_Kth(root,r+2);Splay(y,root);Update_Rev(Key_value);//Splay(Key_value,0);}int Lcp(int l,int r)//操作4,输出从l开始和r开始的两个后缀的LCP{int L = 0,R = len - r + 1;int ans = 0;while(L <= R){int mid = (L + R) >> 1;int x = Get_Kth(root,l);Splay(x,0);int y = Get_Kth(root,l+mid+1);Splay(y,root);unsigned long long k = Hash1[Key_value];x = Get_Kth(root,r);Splay(x,0);y = Get_Kth(root,r+mid+1);Splay(y,root);if(k == Hash1[Key_value]){ans = mid;L = mid + 1;}else R = mid - 1;}return ans;}void solve(int m){init(strlen(str));while(m--){int ope,p1,p2;scanf("%d",&ope);if(ope == 1){scanf("%d%d",&p1,&p2);insert(p1,p2);}else if(ope == 2){scanf("%d",&p1);remove(p1);}else if(ope == 3){scanf("%d%d",&p1,&p2);Reversal(p1,p2);}else{scanf("%d%d",&p1,&p2);printf("%d\n",Lcp(p1,p2));}}}}spt;int main(){//freopen("in.txt","r",stdin);int n,m;mi[0] = 1;for(int i = 1;i < maxn;i++){mi[i] = mimi*mi[i-1];}while(scanf("%d%d",&n,&m)==2){scanf("%s",str);spt.solve(m);}return 0;}

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Jewel Magic UVa 11996