隐藏
「bzoj3682」Phorni - 后缀平衡树 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「bzoj3682」Phorni - 后缀平衡树

题目大意

    有一个字符串$s$,有$n$个结点,每个结点对应到字符串上的一个位置,每次在字符串前加入一个字符或修改结点对应的位置,询问编号在$[l,r]$中所对应位置后缀字符串最小的点编号。


题目分析

后缀平衡树模板题。
用平衡树维护后缀大小关系,用线段树维护最小的点即可。
没有人的算术很像。

我使用treap实现,每次旋转重新计算映射,也可以用替罪羊树实现。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

const int maxn=500005,maxc=300005;

mt19937 g(rand());

struct Tree {
int child[2];
int val,d;
double num;
};

struct Treap {
Tree tree[maxc];
int size,root;
#define d(x) tree[x].d
#define ls(x) tree[x].child[0]
#define rs(x) tree[x].child[1]
#define val(x) tree[x].val
#define num(x) tree[x].num
int newnode(int val) {
int now=++size;
val(now)=val;
d(now)=g()%maxc;
return now;
}
void rebuild(int &index,double l,double r) { //重新计算映射
if(!index)return;
double mid=(l+r)/2;
num(index)=mid;
rebuild(ls(index),l,mid);
rebuild(rs(index),mid,r);
}
void rotate(int &index,bool side,double l,double r) {
int son=tree[index].child[side^1];
tree[index].child[side^1]=tree[son].child[side];
tree[son].child[side]=index;
index=son;
rebuild(index,l,r);
}
int cmp(int x,int y) {
return val(x)>val(y)||(val(x)==val(y)&&num(x-1)>=num(y-1));
}
void insert(int &index,double l,double r,int New) {
double mid=(l+r)/2;
if(!index) {
index=New;
num(index)=mid;
return;
}
bool side=cmp(New,index);
int &son=tree[index].child[side];
if(side==0)insert(son,l,mid,New);
else insert(son,mid,r,New);
if(d(index)<d(son))rotate(index,side^1,l,r);
}
void insert(int val) {
int New=newnode(val);
insert(root,0,1,New);
}
} treap;

int pos[maxn];

struct STree {
int left,right,min;
STree(int l=0,int r=0,int m=-1):left(l),right(r),min(m) {}
};

struct Segment_Tree {
STree tree[maxn*4];
#define ls index<<1
#define rs index<<1|1
void build(int index,int Left,int Right) {
tree[index]=STree(Left,Right);
if(Left==Right) {
tree[index].min=Left;
return;
}
int mid=(Left+Right)>>1;
build(ls,Left,mid);
build(rs,mid+1,Right);
push_up(index);
}
void push_up(int index) {
tree[index].min=treap.tree[pos[tree[ls].min]].num<=treap.tree[pos[tree[rs].min]].num?tree[ls].min:tree[rs].min;
}
void update(int index,int target) {
if(target<tree[index].left||target>tree[index].right)return;
if(tree[index].left==tree[index].right)return;
update(ls,target);
update(rs,target);
push_up(index);
}
int query(int index,int Left,int Right) {
if(Right<tree[index].left||Left>tree[index].right)return -1;
if(Left<=tree[index].left&&Right>=tree[index].right)return tree[index].min;
int l=query(ls,Left,Right),r=query(rs,Left,Right);
if(l==-1)return r;
if(r==-1)return l;
return treap.tree[pos[l]].num<=treap.tree[pos[r]].num?l:r;
}
} st;

int n,m,len,type,lastans;
char s[100005];

int main() {
n=Get_Int();
m=Get_Int();
len=Get_Int();
type=Get_Int();
scanf("%s",s+1);
for(int i=len; i>=1; i--)treap.insert(s[i]-'a'+1);
for(int i=1; i<=n; i++)pos[i]=Get_Int();
st.build(1,1,n);
while(m--) {
char opt=' ';
while(!isalpha(opt))opt=getchar();
if(opt=='I') {
if(type)treap.insert((lastans^Get_Int())+1);
else treap.insert(Get_Int()+1);
} else if(opt=='C') {
int x=Get_Int(),p=Get_Int();
pos[x]=p;
st.update(1,x);
} else if(opt=='Q') {
int l=Get_Int(),r=Get_Int();
lastans=st.query(1,l,r);
printf("%d\n",lastans);
}
}
return 0;
}
姥爷们赏瓶冰阔落吧~