日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

F. Paper Grading(Trie树+dfs序+二维数点)

發(fā)布時間:2023/12/3 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 F. Paper Grading(Trie树+dfs序+二维数点) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

F. Paper Grading

大佬題解
一般關(guān)于前綴的問題基本都是Trie樹。

首先將所給字符串建立一棵Trie樹,Trie能夠解決一個字符串在一個字符串集合中出現(xiàn)的次數(shù),而查詢前綴次數(shù)只需要找到Trie樹中所給字符末尾的位置,那么其子樹中打標(biāo)記的次數(shù)即前綴次數(shù)。

由于子樹dfs序[L,R]連續(xù),于是把字典樹按照dfs序標(biāo)記,即變成區(qū)間查詢問題[l,r]中[L,R]之間數(shù)的個數(shù),二位偏序問題。

樹套樹(樹狀數(shù)組套下標(biāo)線段樹)即可解決,要動態(tài)開點(diǎn)!

#include<iostream> using namespace std; const int N=200010; char s[N]; int n,q,pos[N]; // Trie樹 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; // 動態(tài)開點(diǎn)線段樹 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ù)組 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),把時間軸當(dāng)作一維即靜態(tài)三維數(shù)點(diǎn),cdq分治+樹狀數(shù)組

#include<iostream> #include<algorithm> using namespace std; const int N=200010; char s[N]; int n,m,pos[N]; // Trie樹 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; }

寫代碼過程中總是弄不清記得東西,每次都是一層一層的想,尤其是dfs序問題,很迷糊,還是要多寫,多積累!!!要不然訓(xùn)練總是掛機(jī)

總結(jié)

以上是生活随笔為你收集整理的F. Paper Grading(Trie树+dfs序+二维数点)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。