国际惯例的题面:

考虑如果没有强制在线我们能怎么水掉这个题,先构造出字符串,各种方法求一下后缀数组,然后线段树维护区间rank最小的位置即可。
然而他要求强制在线,支持插入后缀,并比较后缀大小(求rank)的数据结构,当然就是后缀平衡树啦。
于是插入字符串的操作,我们只需要在后缀平衡树上插入这个后缀。此时不需要对线段树进行修改,因为线段树中任何一个位置均不包含新插入的这个后缀(保证信息合法)。
什么你说插入会改变每个后缀的rank值?没关系我们不需要知道每个后缀的rank具体是多少,我们只需要它们的相对大小关系,这个显然是不会改变的是吧。
(你还不明白?先去A了"Bzoj3600: 没有人的算术"再说。什么你A了还不明白?丢人!褪裙吧!)
然后对线段树的修改和查询就显然了。
(话说这题treap不旋比旋转快,替罪羊alpha设为1最快,某大佬裸BST直接AC都是什么鬼啊)

代码:

 #include<cstdio>
#include<algorithm>
#include<cctype>
const int maxe=1e6+1e2;
const double alpha = 0.85; char in[maxe];
int at[maxe]; // suffix i's node .
double v[maxe]; struct SuffixBalancedTree { // we should insert 0 as the minimal suffix .
int lson[maxe],rson[maxe],siz[maxe],sf[maxe],root,cnt;
int seq[maxe],sql;
int fail,failfa;
double vfl,vfr; inline bool cmp(int x,int y) {
if( !x || !y ) return !x;
if( in[x] != in[y] ) return in[x] < in[y];
else return v[at[x-]] < v[at[y-]];
}
inline void upgrade(int pos,double l,double r) {
siz[pos] = siz[lson[pos]] + siz[rson[pos]] + ;
if( std::max( siz[lson[pos]] , siz[rson[pos]] ) > siz[pos] * alpha ) fail = pos , failfa = - , vfl = l , vfr = r;
else if( fail == lson[pos] || fail == rson[pos] ) failfa = pos;
}
inline void insert(int &pos,double l,double r,const int &id) {
if( !pos ) {
v[at[id]=pos=++cnt]= ( l + r ) / 2.0 , siz[pos] = , sf[pos] = id;
return;
} const double vmid = ( l + r ) / 2.0;
if( cmp(sf[pos],id) ) insert(rson[pos],vmid,r,id) , upgrade(pos,l,r); // id > sf[pos] .
else insert(lson[pos],l,vmid,id) , upgrade(pos,l,r);
}
inline int rebuild(int ll,int rr,double l,double r) {
const int mid = ( ll + rr ) >> , pos = seq[mid];
const double vmid = ( l + r ) / 2.0; v[pos] = vmid , siz[pos] = rr - ll + ;
if( ll < mid ) lson[pos] = rebuild(ll,mid-,l,vmid);
if( mid < rr ) rson[pos] = rebuild(mid+,rr,vmid,r);
return pos;
}
inline void dfs(int pos) {
if(lson[pos]) dfs(lson[pos]);
seq[++sql] = pos;
if(rson[pos]) dfs(rson[pos]);
lson[pos] = rson[pos] = siz[pos] = ;
}
inline void insert(const int &id) {
fail = , failfa = - , insert(root,,,id);
if(fail) {
sql = , dfs(fail);
if( ~failfa ) {
if( fail == lson[failfa] ) lson[failfa] = rebuild(,sql,vfl,vfr);
else rson[failfa] = rebuild(,sql,vfl,vfr);
} else root = rebuild(,sql,,);
}
}
}sbt; int cov[maxe>>]; struct SegmentTree {
int mx[maxe<<];
#define lson(pos) (pos<<1)
#define rson(pos) (pos<<1|1)
inline bool cmp(int a,int b) {
if( cov[a] == cov[b] ) return a < b;
return v[at[cov[a]]] < v[at[cov[b]]];
}
inline void upgrade(int pos) {
mx[pos] = cmp(mx[lson(pos)],mx[rson(pos)]) ? mx[lson(pos)] : mx[rson(pos)];
}
inline void build(int pos,int l,int r) {
if( l == r ) return void( mx[pos] = l );
const int mid = ( l + r ) >> ;
build(lson(pos),l,mid) , build(rson(pos),mid+,r) , upgrade(pos);
}
inline void update(int pos,int l,int r,const int &tar) {
if( l == r ) return; // nothing to update .
const int mid = ( l + r ) >> ;
if( tar <= mid ) update(lson(pos),l,mid,tar);
else update(rson(pos),mid+,r,tar);
upgrade(pos);
}
inline int query(int pos,int l,int r,const int &ll,const int &rr) {
if( ll <= l && r <= rr ) return mx[pos];
const int mid = ( l + r ) >> ;
if( rr <= mid ) return query(lson(pos),l,mid,ll,rr);
else if( ll > mid ) return query(rson(pos),mid+,r,ll,rr);
const int ql = query(lson(pos),l,mid,ll,rr) , qr = query(rson(pos),mid+,r,ll,rr);
return cmp(ql,qr) ? ql : qr;
}
}sgt; inline char nextchar() {
static const int BS = << ;
static char buf[BS],*st=buf+BS,*ed=st;
if( st == ed ) ed = buf + fread(st=buf,,BS,stdin);
return st == ed ? - : *st++;
}
inline void getstr(char* s) {
char c;
while( !isalpha(c=nextchar()) );
do *s++=c; while( isalpha(c=nextchar()) );
}
inline char realchar() {
char c;
while( !isalpha(c=nextchar()) );
return c;
}
inline int getint() {
int ret = , ch;
while( !isdigit(ch=nextchar()) );
do ret=ret*+ch-''; while( isdigit(ch=nextchar()) );
return ret;
} int main() {
static int n,m,len,tpe,lastans;
n = getint() , m = getint() , len = getint() , tpe = getint() , getstr(in+) , std::reverse(in+,in++len);
for(int i=;i<=len;i++) in[i] -= 'a' , sbt.insert(i);
for(int i=;i<=n;i++) cov[i] = getint();
sgt.build(,,n);
for(int i=,o,c,x,l,r;i<=m;i++) {
o = realchar();
if( o == 'I' ) {
c = getint();
if( tpe ) c ^= lastans;
in[++len] = c , sbt.insert(len);
} else if( o == 'C' ) x = getint() , cov[x] = getint() , sgt.update(,,n,x);
else if( o == 'Q' ) l = getint() , r = getint() , printf("%d\n",lastans=sgt.query(,,n,l,r));
}
return ;
}

思い出して 優しいハウリング
回忆起 温柔的振鸣
奏でる声 未来を示してた
演奏之声 昭示了未来
思い出して 優しいハウリング
回忆起 温柔的共鸣
遅くはない そう教えてくれた
永远不会太迟 你是这样教我的
今までの過ちすべて
至今经历的一切
巻き戻すことなんて出来はしない
已不能倒带
間違いを認める勇気
不懂得承认错误的勇气
知らなかったよ 凄く不器用に 生きてた
十分笨拙的生存着

3682: Phorni 后缀平衡树 线段树的更多相关文章

  1. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  2. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  3. 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)

    题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...

  4. BZOJ1396: 识别子串(后缀自动机 线段树)

    题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...

  5. [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)

    https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...

  6. 洛谷P4493 [HAOI2018]字串覆盖(后缀自动机+线段树+倍增)

    题面 传送门 题解 字符串就硬是要和数据结构结合在一起么--\(loj\)上\(rk1\)好像码了\(10k\)的样子-- 我们设\(L=r-l+1\) 首先可以发现对于\(T\)串一定是从左到右,能 ...

  7. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

  8. 【BZOJ4556】[TJOI2016&HEOI2016] 字符串(后缀自动机+线段树合并+二分)

    点此看题面 大致题意: 给你一个字符串\(s\),每次问你一个子串\(s[a..b]\)的所有子串和\(s[c..d]\)的最长公共前缀. 二分 首先我们可以发现一个简单性质,即要求最长公共前缀,则我 ...

  9. bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并)

    bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并) bzoj Luogu 给出一个字符串 $ S $ 及 $ q $ 次询问,每次询问一个字符串 $ T $ ...

随机推荐

  1. 内核中container_of宏的详细分析【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637597.html 内核中container_of宏的详细分析 16年2月28日09:00:37 内核中 ...

  2. input 子系统架构总结【转】

    Linux输入子系统(Input Subsystem) 转自:http://blog.csdn.net/lbmygf/article/details/7360084 Linux 的输入子系统不仅支持鼠 ...

  3. Mac环境变量配置错了以后初始化的方法

    转自:https://blog.csdn.net/or_7r_ccl/article/details/50886223 配置过安卓开发环境,改过bash_profile这个文件,最后不知怎么的只有cd ...

  4. wget安装pip和pip3

    pip的安装 1.1 pip下载 wget "https://pypi.python.org/packages/source/p/pip/pip-1.5.4.tar.gz#md5=834b2 ...

  5. saltstack自动化运维系列11基于etcd的saltstack的自动化扩容

    saltstack自动化运维系列11基于etcd的saltstack的自动化扩容 自动化运维-基于etcd加saltstack的自动化扩容# tar -xf etcd-v2.2.1-linux-amd ...

  6. 通达OA系统故障解决案例记录

    案例1: 现象:在人员访问量大的时候OA系统经卡死,并且经常宕机,需要启动apache服务 优化配置如下: D:\MYOA\conf\http.conf 修改参数如下: <IfModule mp ...

  7. python中type、object与class之间关系(一切皆对象)

    object是最顶层基类 object是type的实例,而type又继承object type是自身的实例 >>> class Student: ... pass ... >& ...

  8. liunx centox ssh 配置

    https://www.cnblogs.com/xubing-613/p/6844564.html 一. 查看是否安装了ssh: rpm -qa | grep ssh 重启ssh  service s ...

  9. Laravel collection 报错 join(): Invalid arguments passed

    混淆了 array 与 collection,join 并不支持 collection. array 与 collection 不同的 join 实现 collect([1, 2, 3, 4, 5]) ...

  10. GItlab作CI/CD时,想快点,有啥招?

    如果希望.m2文件有存缓,或是不要每次从dockerhub上找镜像(有的是本地镜像,远程没有的) 那么,gitlab-runner的config.toml初步优化文件如下: concurrent = ...