1. 程式人生 > >BZOJ5408: string(廣義後綴自動機,LCT)

BZOJ5408: string(廣義後綴自動機,LCT)

cal pan sta sum amp har tps 解題思路 rotate

傳送門

解題思路:

首先在後綴樹上,確定了一個節點就相當於確定了一個串,那麽一個點對應的串在另外一個點對應的串產生貢獻,當且僅當這個點在當前點子樹內。

那麽考慮一個新的點在串中對串答案的貢獻在一條樹鏈上或者反過來說,就是產生貢獻的點在這個點子樹內。

考慮n非常小,貢獻可以單獨算,再配合BZOJ2555的啟發,這道題就可以使用LCT輕松地解決了。

代碼:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define lll tr[spc].ch[0]
  5
#define rrr tr[spc].ch[1] 6 #define ls ch[0] 7 #define rs ch[1] 8 typedef long long lnt; 9 struct trnt{ 10 int ch[2]; 11 int fa; 12 int val[21]; 13 int lzt[21]; 14 bool anc; 15 }tr[1000000]; 16 struct sant{ 17 int tranc[26]; 18 int pre; 19 int
len; 20 }s[1000000]; 21 int n,m; 22 lnt sum; 23 int siz; 24 int type; 25 int lastans; 26 int pos[21][200010]; 27 char str[400000]; 28 bool whc(int spc) 29 { 30 return tr[tr[spc].fa].rs==spc; 31 } 32 void add(int spc,int no,int v) 33 { 34 if(!spc)return ; 35 tr[spc].val[no]+=v;
36 tr[spc].lzt[no]+=v; 37 return ; 38 } 39 void pushdown(int spc) 40 { 41 for(int i=1;i<=n;i++) 42 { 43 if(tr[spc].lzt[i]) 44 { 45 add(lll,i,tr[spc].lzt[i]); 46 add(rrr,i,tr[spc].lzt[i]); 47 tr[spc].lzt[i]=0; 48 } 49 } 50 } 51 void recal(int spc) 52 { 53 if(!tr[spc].anc)recal(tr[spc].fa); 54 pushdown(spc); 55 return ; 56 } 57 void rotate(int spc) 58 { 59 int f=tr[spc].fa; 60 bool k=whc(spc); 61 tr[f].ch[k]=tr[spc].ch[!k]; 62 tr[spc].ch[!k]=f; 63 if(tr[f].anc) 64 { 65 tr[f].anc=false; 66 tr[spc].anc=true; 67 }else tr[tr[f].fa].ch[whc(f)]=spc; 68 tr[spc].fa=tr[f].fa; 69 tr[f].fa=spc; 70 tr[tr[f].ch[k]].fa=f; 71 return ; 72 } 73 void splay(int spc) 74 { 75 recal(spc); 76 while(!tr[spc].anc) 77 { 78 int f=tr[spc].fa; 79 if(tr[f].anc) 80 { 81 rotate(spc); 82 return ; 83 } 84 if(whc(spc)^whc(f))rotate(spc); 85 else rotate(f); 86 rotate(spc); 87 } 88 return ; 89 } 90 void access(int spc) 91 { 92 int lst=0; 93 while(spc) 94 { 95 splay(spc); 96 tr[rrr].anc=true; 97 tr[lst].anc=false; 98 rrr=lst; 99 lst=spc; 100 spc=tr[spc].fa; 101 } 102 return ; 103 } 104 void ADD(int from,int to,int cmd) 105 { 106 recal(from); 107 for(int i=1;i<=n;i++) 108 { 109 if(tr[from].val[i]) 110 { 111 add(to,i,tr[from].val[i]*cmd); 112 } 113 } 114 return ; 115 } 116 void link(int x,int f) 117 { 118 access(f); 119 splay(f); 120 splay(x); 121 ADD(x,f,1); 122 tr[x].fa=f; 123 return ; 124 } 125 void cut(int spc) 126 { 127 access(spc); 128 splay(spc); 129 int spc_=lll; 130 lll=tr[spc_].fa=0; 131 tr[spc_].anc=true; 132 splay(spc_); 133 ADD(spc,spc_,-1); 134 return ; 135 } 136 int decode(int c) 137 { 138 if(type)return (c xor lastans)%10; 139 return c; 140 } 141 int Insert(int fin,int no,int c) 142 { 143 if(s[fin].tranc[c]&&s[s[fin].tranc[c]].len==s[fin].len+1) 144 { 145 int spc=s[fin].tranc[c]; 146 access(spc); 147 splay(spc); 148 add(spc,no,1); 149 return spc; 150 } 151 int nwp,lsp,nwq,lsq,flag=0; 152 nwp=++siz;tr[nwp].val[no]=1; 153 s[nwp].len=s[fin].len+1; 154 for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)s[lsp].tranc[c]=nwp; 155 if(!lsp) 156 { 157 s[nwp].pre=1; 158 link(nwp,1); 159 }else{ 160 lsq=s[lsp].tranc[c]; 161 if(s[lsq].len==s[lsp].len+1) 162 { 163 s[nwp].pre=lsq; 164 link(nwp,lsq); 165 }else{ 166 if(s[nwp].len==s[lsp].len+1)flag=1; 167 nwq=++siz; 168 s[nwq]=s[lsq]; 169 s[nwq].len=s[lsp].len+1; 170 s[nwp].pre=s[lsq].pre=nwq; 171 cut(lsq); 172 link(nwq,s[nwq].pre); 173 link(nwp,nwq); 174 link(lsq,nwq); 175 while(s[lsp].tranc[c]==lsq) 176 { 177 s[lsp].tranc[c]=nwq; 178 lsp=s[lsp].pre; 179 } 180 } 181 } 182 sum+=s[nwp].len-s[s[nwp].pre].len; 183 if(flag)return nwq; 184 return nwp; 185 } 186 void init(void) 187 { 188 for(int i=1;i<=500000;i++)tr[i].anc=true; 189 siz=1; 190 return ; 191 } 192 int query(char *a) 193 { 194 int len=strlen(a+1); 195 int spc=1; 196 for(int i=1;i<=len;i++) 197 { 198 int c=a[i]-0; 199 spc=s[spc].tranc[c]; 200 if(!spc)return 0; 201 } 202 int ans=-1; 203 recal(spc); 204 for(int i=1;i<=n;i++) 205 ans=std::max(ans,tr[spc].val[i]); 206 return ans; 207 } 208 int main() 209 { 210 scanf("%d%d",&n,&type); 211 init(); 212 for(int i=1;i<=n;i++) 213 { 214 scanf("%s",str+1); 215 int len=strlen(str+1); 216 pos[i][0]=1; 217 for(int j=1;j<=len;j++) 218 pos[i][0]=Insert(pos[i][0],i,str[j]-0); 219 } 220 scanf("%d",&m); 221 for(int r=1;r<=m;r++) 222 { 223 for(int i=1;i<=n;i++)pos[i][r]=pos[i][r-1]; 224 int opt; 225 scanf("%d",&opt); 226 if(opt==1) 227 { 228 int x,y; 229 scanf("%d%d",&x,&y); 230 y=decode(y); 231 pos[x][r]=Insert(pos[x][r],x,y); 232 } 233 if(opt==2) 234 { 235 int x,y,z; 236 scanf("%d%d%d",&x,&y,&z); 237 int spc=pos[x][y]; 238 recal(spc); 239 lastans=tr[spc].val[z]; 240 printf("%d\n",lastans); 241 } 242 if(opt==3)printf("%lld\n",sum); 243 if(opt==4) 244 { 245 scanf("%s",str+1); 246 lastans=query(str); 247 printf("%d\n",lastans); 248 } 249 } 250 return 0; 251 }

BZOJ5408: string(廣義後綴自動機,LCT)