Wannafly挑战赛10F-小H和遗迹【Trie,树状数组】
生活随笔
收集整理的這篇文章主要介紹了
Wannafly挑战赛10F-小H和遗迹【Trie,树状数组】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://ac.nowcoder.com/acm/contest/72/F
題目大意
nnn個字符串,包括小寫字母和#\##。其中#\##可以替換為任意字符串。求有多少對字符串可能相同。
保證每個字符串至少有一個#\##。
2≤n≤500000,∑i=1n∣si∣≤1062\leq n\leq 500000,\sum_{i=1}^n |s_i|\leq 10^62≤n≤500000,∑i=1n?∣si?∣≤106
解題思路
因為可以替換為任意字符串,所以只需要考慮第一個#\##前和最后一個#\##后的部分。
在仔細考慮一下,這個字符串分成前后的兩個部分s,ts,ts,t。數對(x,y)(x,y)(x,y)滿足條件當且僅當sxs_xsx?是sys_ysy?的前綴,或者sys_ysy?是sxs_xsx?的前綴,且txt_xtx?是tyt_yty?的后綴,或者tyt_yty?是txt_xtx?的后綴。
放到兩棵TrieTrieTrie樹上就是都有祖先關系就好了,直接跑第一棵上,然后用兩個樹狀數組在第二棵樹上維護就好了。
時間復雜度O(mlog?m)O(m\log m)O(mlogm)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define lowbit(x) (x&-x) using namespace std; const int N=1e6+10; int n,cnt,pos[N],dfn[N],ed[N]; long long ans;char s[N]; vector<int> G[N]; struct TreeBinary{int t[N];void Change(int x,int val){while(x<=cnt){t[x]+=val;x+=lowbit(x);}return;}int Ask(int x){int ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;} }Bf,Bs; struct Trie{int t[N][26],m=1;int Insert(char *s,int n){int x=1;for(int i=1;i<=n;i++){if(s[i]=='#')break;int c=s[i]-'a';if(!t[x][c])t[x][c]=++m;x=t[x][c];}return x;} }Tp,Ts; void dfs(int x){dfn[x]=++cnt;for(int i=0;i<26;i++)if(Ts.t[x][i])dfs(Ts.t[x][i]);ed[x]=cnt; } void work(int x){for(int i=0;i<G[x].size();i++){int p=G[x][i];ans+=Bf.Ask(dfn[pos[p]]);Bf.Change(dfn[pos[p]],1);Bf.Change(ed[pos[p]]+1,-1);ans+=Bs.Ask(ed[pos[p]])-Bs.Ask(dfn[pos[p]]); Bs.Change(dfn[pos[p]],1);}for(int i=0;i<26;i++)if(Tp.t[x][i])work(Tp.t[x][i]);for(int i=0;i<G[x].size();i++){int p=G[x][i];Bs.Change(dfn[pos[p]],-1);Bf.Change(dfn[pos[p]],-1);Bf.Change(ed[pos[p]]+1,1);} } int main() {scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%s",s+1);int l=strlen(s+1);int x=Tp.Insert(s,l);G[x].push_back(i);reverse(s+1,s+1+l);pos[i]=Ts.Insert(s,l);}dfs(1);work(1);printf("%lld\n",ans);return 0; }總結
以上是生活随笔為你收集整理的Wannafly挑战赛10F-小H和遗迹【Trie,树状数组】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 笔记本散热底座有用吗 是怎么实现散热的
- 下一篇: P4716-[模板]最小树形图