传说中的对联算法套路题,先贴代码,题解咕咕咕。
上联:AC自动机fail树dfs序建可持久化线段树
下联:后缀自动机next指针dag图上跑SG函数
上联这几个算法学了很久了,今天才把这题做了,虽然csl说是套路题,但感觉真的很难,下联的还差后缀自动机正在学,学好了再贴代码。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair <int,int> pii; #define rep(i,x,y) for(int i=x;i<y;i++) #define rept(i,x,y) for(int i=x;i<=y;i++) #define per(i,x,y) for(int i=x;i>=y;i--) #define pb push_back #define mp make_pair #define fi first #define se second #define de(x) cout<< #x<<" = "<<x<<" " #define dd(x) cout<< #x<<" = "<<x<<" " #define debug() cout<<"I love Miyamizu Mitsuha forever! " #define mes(a,b) memset(a,b,sizeof a) const int inf=0x3f3f3f3f; const int maxn=2e5+5; vector<int> v[maxn]; int p[maxn]; class Trie { public: Trie() { cnt=1; } int cnt; int trie[maxn][26]; int fail[maxn],fa[maxn]; int insert(string s) { int len=s.size(); int pos=0; rep(i,0,len) { int next=s[i]-'a'; if(!trie[pos][next]) trie[pos][next]=cnt++; fa[trie[pos][next]]=pos; pos=trie[pos][next]; } return pos; } void getfail() { queue<int> q; rep(i,0,26) { if(trie[0][i]) { fail[trie[0][i]]=0; v[0].pb(trie[0][i]); q.push(trie[0][i]); } } while(!q.empty()) { int pos=q.front(); q.pop(); rep(i,0,26) { if(trie[pos][i]) { fail[trie[pos][i]]=trie[fail[pos]][i]; v[trie[fail[pos]][i]].pb(trie[pos][i]); q.push(trie[pos][i]); } else { trie[pos][i]=trie[fail[pos]][i]; } } } } }ac; int dfsl[maxn],dfsr[maxn],dfspos=0; void dfs(int id) { dfsl[id]=dfsr[id]=++dfspos; rep(i,0,v[id].size()) { dfs(v[id][i]); dfsr[id]=dfsr[v[id][i]]; } } int root[maxn]; class element { public: int lson,rson,val; }; class Tree { public: int cnt=0; element tree[maxn<<5]; int build(int l,int r) { int id=++cnt; tree[id].val=0; if(l==r) return id; int mid=(l+r)>>1; tree[id].lson=build(l,mid); tree[id].rson=build(mid+1,r); return id; } void update(int &id,int p,int lt,int rt,int plus=1) { if(lt>p||rt<p) return ; int newid=++cnt; if(lt==rt) { tree[newid].val=tree[id].val+plus; id=newid; return ; } tree[newid]=tree[id]; id=newid; int mid=(lt+rt)>>1; update(tree[newid].lson,p,lt,mid,plus); update(tree[newid].rson,p,mid+1,rt,plus); tree[newid].val=tree[tree[newid].lson].val+tree[tree[newid].rson].val; } int query(int id,int l,int r,int lt,int rt) { if(lt>=l&&rt<=r) return tree[id].val; if(lt>r||rt<l) return 0; int mid=(lt+rt)>>1; return query(tree[id].lson,l,r,lt,mid)+query(tree[id].rson,l,r,mid+1,rt); } }t; int st[maxn],cnt=0; int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int n,q; cin>>n>>q; rept(i,1,n) { string s; cin>>s; p[i]=ac.insert(s); } ac.getfail(); dfs(0); root[cnt++]=t.build(0,ac.cnt); st[0]=root[0]; rept(i,1,n) { int pos=p[i]; while(pos) { root[cnt+1]=root[cnt]; cnt++; t.update(root[cnt],dfsl[pos],0,ac.cnt,1); pos=ac.fa[pos]; } st[i]=root[cnt]; } while(q--) { int l,r,k; cin>>l>>r>>k; cout<<t.query(st[r],dfsl[p[k]],dfsr[p[k]],0,ac.cnt)-t.query(st[l-1],dfsl[p[k]],dfsr[p[k]],0,ac.cnt)<<" "; } return 0; }