3682: Phorni 后缀平衡树 线段树

国际惯例的题面:


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

代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cctype>
  4 const int maxe=1e6+1e2;
  5 const double alpha = 0.85;
  6 
  7 char in[maxe];
  8 int at[maxe]; // suffix i's node .
  9 double v[maxe];
 10 
 11 struct SuffixBalancedTree { // we should insert 0 as the minimal suffix .
 12     int lson[maxe],rson[maxe],siz[maxe],sf[maxe],root,cnt;
 13     int seq[maxe],sql;
 14     int fail,failfa;
 15     double vfl,vfr;
 16     
 17     inline bool cmp(int x,int y) {
 18         if( !x || !y ) return !x;
 19         if( in[x] != in[y] ) return in[x] < in[y];
 20         else return v[at[x-1]] < v[at[y-1]];
 21     }
 22     inline void upgrade(int pos,double l,double r) {
 23         siz[pos] = siz[lson[pos]] + siz[rson[pos]] + 1;
 24         if( std::max( siz[lson[pos]] , siz[rson[pos]] ) > siz[pos] * alpha ) fail = pos , failfa = -1 , vfl = l , vfr = r;
 25         else if( fail == lson[pos] || fail == rson[pos] ) failfa = pos;
 26     }
 27     inline void insert(int &pos,double l,double r,const int &id) {
 28         if( !pos ) {
 29             v[at[id]=pos=++cnt]= ( l + r ) / 2.0 , siz[pos] = 1 , sf[pos] = id;
 30             return;
 31         } const double vmid = ( l + r ) / 2.0;
 32         if( cmp(sf[pos],id) ) insert(rson[pos],vmid,r,id) , upgrade(pos,l,r); // id > sf[pos] .
 33         else insert(lson[pos],l,vmid,id) , upgrade(pos,l,r);
 34     }
 35     inline int rebuild(int ll,int rr,double l,double r) {
 36         const int mid = ( ll + rr ) >> 1 , pos = seq[mid];
 37         const double vmid = ( l + r ) / 2.0; v[pos] = vmid , siz[pos] = rr - ll + 1;
 38         if( ll < mid ) lson[pos] = rebuild(ll,mid-1,l,vmid);
 39         if( mid < rr ) rson[pos] = rebuild(mid+1,rr,vmid,r);
 40         return pos;
 41     }
 42     inline void dfs(int pos) {
 43         if(lson[pos]) dfs(lson[pos]);
 44         seq[++sql] = pos;
 45         if(rson[pos]) dfs(rson[pos]);
 46         lson[pos] = rson[pos] = siz[pos] = 0;
 47     }
 48     inline void insert(const int &id) {
 49         fail = 0 , failfa = -1 , insert(root,0,1,id);
 50         if(fail) {
 51             sql = 0 , dfs(fail);
 52             if( ~failfa ) {
 53                 if( fail == lson[failfa] ) lson[failfa] = rebuild(1,sql,vfl,vfr);
 54                 else rson[failfa] = rebuild(1,sql,vfl,vfr);
 55             } else root = rebuild(1,sql,0,1);
 56         }
 57     }
 58 }sbt;
 59 
 60 int cov[maxe>>1];
 61 
 62 struct SegmentTree {
 63     int mx[maxe<<1];
 64     #define lson(pos) (pos<<1)
 65     #define rson(pos) (pos<<1|1)
 66     inline bool cmp(int a,int b) {
 67         if( cov[a] == cov[b] ) return a < b;
 68         return v[at[cov[a]]] < v[at[cov[b]]];
 69     }
 70     inline void upgrade(int pos) {
 71         mx[pos] = cmp(mx[lson(pos)],mx[rson(pos)]) ? mx[lson(pos)] : mx[rson(pos)];
 72     }
 73     inline void build(int pos,int l,int r) {
 74         if( l == r ) return void( mx[pos] = l );
 75         const int mid = ( l + r ) >> 1;
 76         build(lson(pos),l,mid) , build(rson(pos),mid+1,r) , upgrade(pos);
 77     }
 78     inline void update(int pos,int l,int r,const int &tar) {
 79         if( l == r ) return; // nothing to update .
 80         const int mid = ( l + r ) >> 1;
 81         if( tar <= mid ) update(lson(pos),l,mid,tar);
 82         else update(rson(pos),mid+1,r,tar);
 83         upgrade(pos);
 84     }
 85     inline int query(int pos,int l,int r,const int &ll,const int &rr) {
 86         if( ll <= l && r <= rr ) return mx[pos];
 87         const int mid = ( l + r ) >> 1;
 88         if( rr <= mid ) return query(lson(pos),l,mid,ll,rr);
 89         else if( ll > mid ) return query(rson(pos),mid+1,r,ll,rr);
 90         const int ql = query(lson(pos),l,mid,ll,rr) , qr = query(rson(pos),mid+1,r,ll,rr);
 91         return cmp(ql,qr) ? ql : qr;
 92     }
 93 }sgt;
 94 
 95 inline char nextchar() {
 96     static const int BS = 1 << 21;
 97     static char buf[BS],*st=buf+BS,*ed=st;
 98     if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin);
 99     return st == ed ? -1 : *st++;
100 }
101 inline void getstr(char* s) {
102     char c;
103     while( !isalpha(c=nextchar()) );
104     do *s++=c; while( isalpha(c=nextchar()) );
105 }
106 inline char realchar() {
107     char c;
108     while( !isalpha(c=nextchar()) );
109     return c;
110 }
111 inline int getint() {
112     int ret = 0 , ch;
113     while( !isdigit(ch=nextchar()) );
114     do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) );
115     return ret;
116 }
117 
118 int main() {
119     static int n,m,len,tpe,lastans;
120     n = getint() , m = getint() , len = getint() , tpe = getint() , getstr(in+1) , std::reverse(in+1,in+1+len);
121     for(int i=0;i<=len;i++) in[i] -= 'a' , sbt.insert(i);
122     for(int i=1;i<=n;i++) cov[i] = getint();
123     sgt.build(1,1,n);
124     for(int i=1,o,c,x,l,r;i<=m;i++) {
125         o = realchar();
126         if( o == 'I' ) {
127             c = getint();
128             if( tpe ) c ^= lastans;
129             in[++len] = c , sbt.insert(len);
130         } else if( o == 'C' ) x = getint() , cov[x] = getint() , sgt.update(1,1,n,x);
131         else if( o == 'Q' ) l = getint() , r = getint() , printf("%d\n",lastans=sgt.query(1,1,n,l,r));
132     }
133     return 0;
134 }
View Code



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

posted @ 2018-05-09 21:00  Cmd2001  阅读(456)  评论(0编辑  收藏  举报