F. Paper Grading(Trie树+dfs序+二维数点)
生活随笔
收集整理的這篇文章主要介紹了
F. Paper Grading(Trie树+dfs序+二维数点)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
F. Paper Grading
大佬題解
一般關(guān)于前綴的問(wèn)題基本都是Trie樹(shù)。
首先將所給字符串建立一棵Trie樹(shù),Trie能夠解決一個(gè)字符串在一個(gè)字符串集合中出現(xiàn)的次數(shù),而查詢前綴次數(shù)只需要找到Trie樹(shù)中所給字符末尾的位置,那么其子樹(shù)中打標(biāo)記的次數(shù)即前綴次數(shù)。
由于子樹(shù)dfs序[L,R]連續(xù),于是把字典樹(shù)按照dfs序標(biāo)記,即變成區(qū)間查詢問(wèn)題[l,r]中[L,R]之間數(shù)的個(gè)數(shù),二位偏序問(wèn)題。
樹(shù)套樹(shù)(樹(shù)狀數(shù)組套下標(biāo)線段樹(shù))即可解決,要?jiǎng)討B(tài)開(kāi)點(diǎn)!
#include<iostream> using namespace std; const int N=200010; char s[N]; int n,q,pos[N]; // Trie樹(shù) struct T1 {int tree[N][26],idx;int insert(char s[]){int p=0;for(int i=0;s[i];i++){int t=s[i]-'a';if(!tree[p][t]) tree[p][t]=++idx;p=tree[p][t];}return p;}int find(char s[],int k){int p=0;for(int i=0;i<k;i++){int t=s[i]-'a';if(!tree[p][t]) return -1;p=tree[p][t];}return p;} }Trie; // 動(dòng)態(tài)開(kāi)點(diǎn)線段樹(shù) struct T2 {struct node{int l,r;int sz;}tree[N*40];int root[N],cnt;void update(int &u,int l,int r,int pos,int x){if(!u) u=++cnt;tree[u].sz+=x;if(l==r) return;int mid=l+r>>1;if(pos<=mid) update(tree[u].l,l,mid,pos,x);else update(tree[u].r,mid+1,r,pos,x);}int query(int u,int l,int r,int L,int R){if(!u) return 0;if(L<=l&&r<=R) return tree[u].sz;int mid=l+r>>1;int v=0;if(L<=mid) v+=query(tree[u].l,l,mid,L,R);if(R>mid) v+=query(tree[u].r,mid+1,r,L,R);return v;} }Segment; // dfs序轉(zhuǎn)化為區(qū)間 int dfn[N],sz[N],timestamp; void dfs(int u) {dfn[u]=++timestamp;sz[u]=1;for(int i=0;i<26;i++)if(Trie.tree[u][i]) dfs(Trie.tree[u][i]),sz[u]+=sz[Trie.tree[u][i]]; } // 樹(shù)狀數(shù)組 int lowbit(int x) {return x&-x;} void add(int k,int pos,int x) {for(;k<=n;k+=lowbit(k))Segment.update(Segment.root[k],1,timestamp,pos,x); } int sum(int k,int L,int R) {int res=0;for(;k;k-=lowbit(k))res+=Segment.query(Segment.root[k],1,timestamp,L,R);return res; } int main() {cin>>n>>q;for(int i=1;i<=n;i++){cin>>s;pos[i]=Trie.insert(s);}dfs(0);for(int i=1;i<=n;i++)add(i,dfn[pos[i]],1);while(q--){int op;cin>>op;if(op==1){int u,v;cin>>u>>v;add(u,dfn[pos[u]],-1);add(v,dfn[pos[v]],-1);add(u,dfn[pos[v]],1);add(v,dfn[pos[u]],1);swap(pos[u],pos[v]);}else{int k,l,r;cin>>s;cin>>k>>l>>r;int u=Trie.find(s,k);if(u==-1) cout<<0<<'\n';else{int L=dfn[u],R=dfn[u]+sz[u]-1;cout<<sum(r,L,R)-sum(l-1,L,R)<<'\n';}}}return 0; }cdq分治,帶修改二維數(shù)點(diǎn),把時(shí)間軸當(dāng)作一維即靜態(tài)三維數(shù)點(diǎn),cdq分治+樹(shù)狀數(shù)組
#include<iostream> #include<algorithm> using namespace std; const int N=200010; char s[N]; int n,m,pos[N]; // Trie樹(shù) struct T1 {int tree[N][26],idx;int insert(char s[]){int p=0;for(int i=0;s[i];i++){int t=s[i]-'a';if(!tree[p][t]) tree[p][t]=++idx;p=tree[p][t];}return p;}int find(char s[],int k){int p=0;for(int i=0;i<k;i++){int t=s[i]-'a';if(!tree[p][t]) return -1;p=tree[p][t];}return p;} }Trie; // dfs序轉(zhuǎn)化為區(qū)間 int dfn[N],sz[N],timestamp; void dfs(int u) {dfn[u]=++timestamp;sz[u]=1;for(int i=0;i<26;i++)if(Trie.tree[u][i]) dfs(Trie.tree[u][i]),sz[u]+=sz[Trie.tree[u][i]]; } int ans[N]; struct node {int op;int a,b,c,cnt;int sign,id; }q[N*5]; int st[N]; bool cmpb(const node &x,const node &y) {return x.b<y.b||x.b==y.b&&x.op<y.op; } int fw[N]; int lowbit(int x){return x&-x;} void update(int k,int x){for(;k<=timestamp;k+=lowbit(k)) fw[k]+=x;} int query(int k){int res=0;for(;k;k-=lowbit(k)) res+=fw[k];return res;} void solve(int l,int r) {if(l>=r) return;int mid=l+r>>1;solve(l,mid),solve(mid+1,r);int i=l;for(int j=mid+1;j<=r;j++){if(q[j].op==1) continue;while(i<=mid&&q[i].b<=q[j].b){if(q[i].op==1) update(q[i].c,q[i].cnt);i++;}ans[q[j].id]+=q[j].sign*query(q[j].c);}while(i>l){i--;if(q[i].op==1) update(q[i].c,-q[i].cnt);}inplace_merge(q+l,q+mid+1,q+r+1,cmpb); } int main() {cin>>n>>m;for(int i=1;i<=n;i++){cin>>s;pos[i]=Trie.insert(s);}dfs(0);int cnt=0;for(int i=1;i<=n;i++)q[++cnt]={1,0,i,dfn[pos[i]],1};for(int i=1;i<=m;i++){int op;cin>>op;if(op==1){int u,v;cin>>u>>v;q[++cnt]={1,i,u,dfn[pos[u]],-1};q[++cnt]={1,i,v,dfn[pos[v]],-1};q[++cnt]={1,i,u,dfn[pos[v]],+1};q[++cnt]={1,i,v,dfn[pos[u]],+1};swap(pos[u],pos[v]);}else{st[i]=1;int k,l,r;cin>>s;cin>>k>>l>>r;int u=Trie.find(s,k);if(u==-1) ans[i]=0;else{int L=dfn[u],R=dfn[u]+sz[u]-1;q[++cnt]={2,i,r,R,0,1,i};q[++cnt]={2,i,l-1,R,0,-1,i};q[++cnt]={2,i,r,L-1,0,-1,i};q[++cnt]={2,i,l-1,L-1,0,1,i};}}}solve(1,cnt);for(int i=1;i<=m;i++)if(st[i]) cout<<ans[i]<<'\n';return 0; }寫(xiě)代碼過(guò)程中總是弄不清記得東西,每次都是一層一層的想,尤其是dfs序問(wèn)題,很迷糊,還是要多寫(xiě),多積累!!!要不然訓(xùn)練總是掛機(jī)
總結(jié)
以上是生活随笔為你收集整理的F. Paper Grading(Trie树+dfs序+二维数点)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 横掠的意思 横掠怎么理解
- 下一篇: I. Space Station(has