Processing math: 58%
BZOJ3331: [BeiJing2013]压力 图连通性
BZOJ1130: [POI2008]POD Subdivision of Kingdom 状压+dfs+恶心题

BZOJ3682: Phorni 后缀平衡树+线段树

shinbokuow posted @ 10 年前 in BZOJ with tags 后缀平衡树 线段树 , 2716 阅读

 

题解:

终于会写后缀平衡树了0.0

首先我们要知道Treap是什么东西。Treap是一种二叉平衡树,同时是重量平衡树,也即单次插入删除期望最大影响的子树大小为O(logn)

也就是说,我们可以暴力重新计算该子树的信息而不用担心复杂度爆炸。

考虑利用重量平衡树来处理动态顺序维护问题。

现在有一个序列,你可以在序列中的某个位置插入一个元素,询问就是询问两个元素的先后顺序。

直接利用平衡树可以做到插入、询问均为O(logn)

考虑动态标号法,在平衡树中的每个节点都记录[l,r],这个节点的值为l+r2

如比较两个元素的顺序,只需要比较两个平衡树节点的值就行了,于是是O(1)

现在要插入一个元素,在旋转之后树的形态可能会发生变化,好在最大影响的子树大小为O(logn),所以直接暴力计算子树内的节点的值就行了,于是单次插入复杂度依然为O(logn)

由于重量平衡树深度期望为O(logn),所以需要的权值的值域在long long范围就可以保证完全区分了。

 

后缀平衡树就是维护后缀之间字典序从小到大的有序序列的平衡树。

假如对于字符串S[1,n],已经构造好S[i,n]的后缀平衡树,考虑如何构造S的后缀平衡树。

那么只需插入后缀i-1就行了。

那么在平衡树中进行插入时,就需要比较两个后缀的字典序大小咯。

而我们可以做到O(1),原因在:若两个后缀首字母相同,则同时去掉首字母,转化为已经存在在平衡树中的两个后缀的顺序问题,利用动态标号就能做到O(1)询问;如果首字母不同则显然O(1)完成。

维护后缀平衡树实质上就是一个动态顺序维护问题,因此可以做到O(nlogn)构造,O(1)询问两个后缀的字典序大小,并支持在串的开头插入一个字符。

 

关于平衡树复杂度的证明有时间再说。

 

代码:

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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
 
typedef unsigned long long llu;
 
#define N 1000010
#define ls ch[0]
#define rs ch[1]
struct Node{
    Node*ch[2];
    llu v;
    int ins,p;
}Tnull,*null=&Tnull,mem[N],*G=mem,*get[N],*root=null;
inline Node*newnode(int _ins){
    G->ls=G->rs=null;
    G->ins=_ins;
    G->p=rand();
    return G++;
}
 
typedef pair<int,int> pii;
inline pii Min(pii x,pii y){
    if(x.first==-1)
        return y;
    if(y.first==-1)
        return x;
    if(get[x.first]->v!=get[y.first]->v)
        return get[x.first]->v<get[y.first]->v?x:y;
    return x.second<y.second?x:y;
}
 
#define mp make_pair
 
#define inf ((llu(-1))>>1)
int p[500010];
struct SegmentTree{
    pii A[1048675];
    int M;
    inline void init(int _siz){
        for(M=1;M<(_siz+2);M<<=1);
        for(int i=0;i<(M<<1);++i)
            A[i]=mp(inf,0);
        for(int i=1;i<=_siz;++i)
            A[M+i]=mp(p[i],i);
        for(int i=M-1;i>=1;--i)
            A[i]=Min(A[i<<1],A[i<<1^1]);
    }
    inline void upd(int x,int _ins){
        for(A[x+=M].first=_ins,x>>=1;x;x>>=1)
            A[x]=Min(A[x<<1],A[x<<1^1]);
    }
    inline int query(int tl,int tr){
        pii ans=mp(-1,0);
        for(tl+=M-1,tr+=M+1;tl^tr^1;tl>>=1,tr>>=1){
            if(~tl&1)
                ans=Min(ans,A[tl^1]);
            if(tr&1)
                ans=Min(ans,A[tr^1]);
        }
        return ans.second;
    }
}Seg;
 
char s[N];
inline bool cmp(const int&x,const int&y){
    if(s[x]!=s[y])
        return s[x]>s[y];
    return get[x-1]->v>get[y-1]->v;
}
 
inline void rot(Node*&p,bool d){
    Node*q=p->ch[!d];
    p->ch[!d]=q->ch[d];
    q->ch[d]=p;
    p=q;
}
inline void recalc(Node*p,llu _l,llu _r){
    p->v=(_l+_r)>>1;
    if(p->ls!=null)
        recalc(p->ls,_l,(_l+_r)>>1);
    if(p->rs!=null)
        recalc(p->rs,1+((_l+_r)>>1),_r);
}
 
Node*lastp;
llu lastl,lastr;
inline void insert(Node*&p,int _ins,llu _l,llu _r){
    if(p==null){
        get[_ins]=p=newnode(_ins);
        p->v=(_l+_r)>>1;
        return;
    }
    bool d=cmp(_ins,p->ins);
    if(d==0){
        insert(p->ls,_ins,_l,(_l+_r)>>1);
        if(p->ls->p<p->p){
            rot(p,1);
            lastp=p;
            lastl=_l;
            lastr=_r;
        }
    }
    else{
        insert(p->rs,_ins,1+((_l+_r)>>1),_r);
        if(p->rs->p<p->p){
            rot(p,0);
            lastp=p;
            lastl=_l;
            lastr=_r;
        }
    }
}
 
/*inline void dfs(Node*p){
    if(p->ls!=null)
        dfs(p->ls);
    printf("%d ",p->ins);
    if(p->rs!=null)
        dfs(p->rs);
}*/
 
int main(){
#ifndef ONLINE_JUDGE
    freopen("tt.in","r",stdin);
    freopen("tt.out","w",stdout);
#endif
    int n,m,len,type;
    cin>>n>>m>>len>>type;
    int i;
    scanf("%s",s+1);
    for(i=1;i<=(len>>1);++i)
        swap(s[i],s[len-i+1]);
    for((get[0]=newnode(0))->v=0,i=1;i<=len;++i){
        lastp=null;
        insert(root,i,0,inf);
        if(lastp!=null)
            recalc(lastp,lastl,lastr);
    }
     
    //dfs(root);
    //puts("");
 
    for(i=1;i<=n;++i)
        scanf("%d",&p[i]);
     
    Seg.init(n);
     
    int lastans=0;
     
    char qte[10];
    int x,y;
    while(m--){
        scanf("%s",qte);
        if(qte[0]=='I'){
            scanf("%d",&x);
            if(type)
                x^=lastans;
            s[++len]='a'+x;
            lastp=null;
            insert(root,len,0,inf);
            if(lastp!=null)
                recalc(lastp,lastl,lastr);
        }
        else if(qte[0]=='C'){
            scanf("%d%d",&x,&y);
            Seg.upd(x,y);
        }
        else{
            scanf("%d%d",&x,&y);
            printf("%d\n",lastans=Seg.query(x,y));
        }
    }
     
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter