1. 程式人生 > >bzoj[3881]Divljak(dfs序+樹狀數組+fail樹)

bzoj[3881]Divljak(dfs序+樹狀數組+fail樹)

das 自動機 pos 集合 就是 mem pre ace cst

這道題利用了fail樹的神奇性質————父節點為其子節點的前綴

先對Alice的集合建一個fail樹,

Bob每插入一個串,都將串在自動機上經過的點在樹上打上標記(+1)

每次查詢的答案就是詢問串的結束節點的子樹的貢獻

所以還需要用到樹狀數組來維護dfs序

因為Bob的一個串至多只能對Alice的某一個串做出1的貢獻,所以不能單純加和

要對樹鏈取並

可以將一個Bob串在fail樹上經過的所有點按入棧順序排序,相鄰每兩個點的lca貢獻-1

可以證明,這樣會使每次某個點的子樹內沒有重復貢獻

  1 #include<queue>
  2
#include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n,m,cnt,tot,tp,num; 7 char s[2000005]; 8 bool ed[2000005]; 9 int vis[2000005]; 10 int ed_pos[100005]; 11 int head[2000005]; 12 int fa[2000005]; 13 int dep[2000005]; 14 int grand[2000005]; 15 int siz[2000005
]; 16 int son[2000005]; 17 int ad[4000005]; 18 int stk[4000005]; 19 int tmp[2000005]; 20 struct Trie{ 21 int son[26]; 22 int fail; 23 }tr[2000005]; 24 struct Edge{ 25 int fr; 26 int to; 27 int nxt; 28 }edge[2000005]; 29 struct node{ 30 int in; 31 int out; 32 }pos[2000005];
33 int lowbit(int x){ 34 return x&(-x); 35 } 36 void init(){ 37 memset(head,-1,sizeof(head)); 38 } 39 void addx(int x,int v){ 40 while(x<=2*tot){ 41 ad[x]+=v; 42 x+=lowbit(x); 43 } 44 } 45 int getsum(int x){ 46 int ret=0; 47 while(x){ 48 ret+=ad[x]; 49 x-=lowbit(x); 50 } 51 return ret; 52 } 53 void addedge(int u,int v){ 54 edge[cnt].fr=u; 55 edge[cnt].to=v; 56 edge[cnt].nxt=head[u]; 57 head[u]=cnt++; 58 } 59 void insert(char h[],int mrk){ 60 int now=0; 61 int len=strlen(h+1); 62 for(int i=1;i<=len;i++){ 63 int k=h[i]-a; 64 if(!tr[now].son[k])tr[now].son[k]=++tot; 65 now=tr[now].son[k]; 66 } 67 ed[now]=true; 68 ed_pos[mrk]=now; 69 } 70 void getfail(){ 71 queue<int>que; 72 for(int i=0;i<26;i++){ 73 if(tr[0].son[i]){ 74 addedge(0,tr[0].son[i]); 75 que.push(tr[0].son[i]); 76 } 77 } 78 while(!que.empty()){ 79 int u=que.front(); 80 que.pop(); 81 for(int i=0;i<26;i++){ 82 if(tr[u].son[i]){ 83 tr[tr[u].son[i]].fail=tr[tr[u].fail].son[i]; 84 addedge(tr[tr[u].fail].son[i],tr[u].son[i]); 85 que.push(tr[u].son[i]); 86 } 87 else tr[u].son[i]=tr[tr[u].fail].son[i]; 88 } 89 } 90 } 91 void dfs1(int u){ 92 siz[u]=1;stk[++tp]=u;pos[u].in=tp; 93 for(int i=head[u];i!=-1;i=edge[i].nxt){ 94 int v=edge[i].to; 95 if(v==fa[u])continue; 96 fa[v]=u;dep[v]=dep[u]+1; 97 dfs1(v);siz[u]+=siz[v]; 98 if(siz[v]>siz[son[u]]||(!son[u]))son[u]=v; 99 } 100 stk[++tp]=u;pos[u].out=tp; 101 } 102 void dfs2(int u){ 103 if(u!=son[fa[u]])grand[u]=u; 104 else grand[u]=grand[fa[u]]; 105 for(int i=head[u];i!=-1;i=edge[i].nxt){ 106 int v=edge[i].to; 107 if(v==fa[u])continue; 108 dfs2(v); 109 } 110 } 111 int lca(int x,int y){ 112 while(grand[x]!=grand[y]){ 113 if(dep[grand[x]]<dep[grand[y]])swap(x,y); 114 x=fa[grand[x]]; 115 } 116 if(dep[x]>dep[y])swap(x,y); 117 return x; 118 } 119 int cmp(int a,int b){ 120 return pos[a].in<pos[b].in; 121 } 122 void match(char b[],int tim){ 123 int now=0; 124 int len=strlen(s+1); 125 for(int i=1;i<=len;i++){ 126 int k=b[i]-a; 127 now=tr[now].son[k]; 128 if(vis[now]==tim)continue; 129 vis[now]=tim;tmp[++num]=now; 130 } 131 sort(tmp+1,tmp+num+1,cmp); 132 for(int i=1;i<=num;i++)addx(pos[tmp[i]].in,1); 133 for(int i=1;i<num;i++){ 134 int f=lca(tmp[i],tmp[i+1]); 135 addx(pos[f].in,-1); 136 } 137 } 138 int main(){ 139 init(); 140 scanf("%d",&n); 141 for(int i=1;i<=n;i++){ 142 scanf("%s",s+1); 143 insert(s,i); 144 } 145 getfail();dfs1(0);dfs2(0); 146 scanf("%d",&m); 147 for(int i=1;i<=m;i++){ 148 int ac; 149 scanf("%d",&ac); 150 if(ac==1){ 151 scanf("%s",s+1); 152 num=0;match(s,i); 153 }else{ 154 int p; 155 scanf("%d",&p); 156 int ans=getsum(pos[ed_pos[p]].out)-getsum(pos[ed_pos[p]].in-1); 157 printf("%d\n",ans); 158 } 159 } 160 return 0; 161 }

bzoj[3881]Divljak(dfs序+樹狀數組+fail樹)