BZOJ4545: DQS的trie
https://lydsy.com/JudgeOnline/problem.php?id=4545
分析:
- 对trie用dfs建sam复杂度是(O(n^2))的,因为你不能让一个复杂度带均摊的东西去一直回溯。
- 构造数据卡也很好卡,一条链边全是a,每个点连出去一条不是a的边。
- 于是我们用bfs建sam,这样复杂度是对的?
- 说这道题的做法,第一个询问每次插入时动态维护即可,第二问操作我们用lct维护后缀链接树。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 400050
#define isrt(p) (ch[f[p]][1]!=p&&ch[f[p]][0]!=p)
typedef long long ll;
int ch[N][3],fa[N],len[N],cnt=1,pos[N],n;
ll nowans;
int head[N],to[N],nxt[N],CNT,val[N];
inline void add(int u,int v,int w) {
to[++CNT]=v; nxt[CNT]=head[u]; head[u]=CNT; val[CNT]=w;
}
int tr[N];
struct LCT {
#define ls ch[p][0]
#define rs ch[p][1]
#define get(x) (ch[f[x]][1]==x)
int ch[N][2],tag[N],f[N];
void rotate(int x) {
int y=f[x],z=f[y],k=get(x);
if(!isrt(y)) ch[z][ch[z][1]==y]=x;
ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
ch[x][!k]=y; f[y]=x; f[x]=z;
}
inline void giv(int p,int d) {
tag[p]+=d; tr[p]+=d;
}
inline void pushdown(int p) {
if(tag[p]) {
if(ls) giv(ls,tag[p]);
if(rs) giv(rs,tag[p]);
tag[p]=0;
}
}
void UPD(int p) {
if(!isrt(p)) UPD(f[p]);
pushdown(p);
}
void splay(int x) {
UPD(x);
for(int d;d=f[x],!isrt(x);rotate(x)) {
if(!isrt(d)) rotate(get(x)==get(d)?d:x);
}
}
void access(int p) {
int t=0;
while(p) {
splay(p); rs=t; t=p; p=f[p];
}
}
void cut(int p) {
access(p); splay(p); f[ls]=0; ls=0;
}
void link(int p,int q) {
f[p]=q;
}
}_;
int insert(int x,int lst) {
int p=lst,np,q,nq;
np=++cnt; lst=np;
len[np]=len[p]+1;
for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
if(!p) fa[np]=1,nowans+=len[np],_.link(np,1);
else {
q=ch[p][x];
if(len[q]==len[p]+1) fa[np]=q,nowans+=len[np]-(len[fa[np]]),_.link(np,q);
else {
nq=++cnt;
len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
_.UPD(q); tr[nq]=tr[q];
nowans-=(len[q]-len[fa[q]]);
fa[nq]=fa[q];
_.link(nq,fa[q]);
fa[q]=fa[np]=nq;
_.cut(q); _.link(q,nq); _.link(np,nq);
nowans+=(len[q]-len[fa[q]])+(len[nq]-len[fa[nq]])+(len[np]-len[fa[np]]);
for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}
_.access(lst), _.splay(lst), _.giv(lst,1);
return lst;
}
int Q[N];
bool vis[N];
void bfs(int x) {
int i,l=0,r=0;
Q[r++]=x; vis[x]=1;
while(l<r) {
x=Q[l++];
for(i=head[x];i;i=nxt[i]) if(!vis[to[i]]) {
vis[to[i]]=1; pos[to[i]]=insert(val[i],pos[x]); Q[r++]=to[i];
}
}
}
char w[N];
int main() {
scanf("%*d%d",&n);
int i,x,y;
pos[1]=1;
char oo[10];
for(i=1;i<n;i++) {
scanf("%d%d%s",&x,&y,oo+1);
add(x,y,oo[1]-'a'),add(y,x,oo[1]-'a');
}
bfs(1);
int m;
scanf("%d",&m);
int sz;
while(m--) {
int opt;
scanf("%d",&opt);
if(opt==1) {
printf("%lld
",nowans);
}else if(opt==2) {
int rt;
scanf("%d%d",&rt,&sz); head[rt]=0;
for(i=1;i<sz;i++) {
scanf("%d%d%s",&x,&y,oo+1);
add(x,y,oo[1]-'a'), add(y,x,oo[1]-'a');
}
bfs(rt);
}else {
scanf("%s",w+1);
int k=strlen(w+1),p=1;
for(i=1;i<=k;i++) {
x=w[i]-'a';
if(ch[p][x]) p=ch[p][x];
else {p=ch[p][x]; break;}
}
if(!p) {puts("0");continue ;}
_.splay(p);
printf("%d
",tr[p]);
}
}
}