[學習筆記]二進位制分組
阿新 • • 發佈:2018-12-26
1、CF710F String Set Queries
AC自動機+二進位制分組。
二進位制分組好像可以搞很多強制線上的題目,比如這題。
利用二進位制分組思想,維護一個 \(siz\) 從大到小的單調棧,若 \(siz_{top}=siz_{top-1}\) 就一直暴力合併兩個 \(AC\) 自動機並求出新 \(AC\) 自動機的 \(fail\) 指標。
\(Code\ Below:\)
#include <bits/stdc++.h> using namespace std; const int maxn=300000+10; int n;char s[maxn]; struct Aho_Corasick_Automaton{ int ch[maxn][26],vis[maxn][26],fail[maxn],num[maxn],sum[maxn],siz[maxn],rt[maxn],top,cnt; void merge(int &x,int y){ if(x==0||y==0){ x=x+y; return ; } num[x]+=num[y]; for(int i=0;i<26;i++) merge(ch[x][i],ch[y][i]); } void getfail(int p){ queue<int> q; for(int c=0;c<26;c++){ if(ch[p][c]){ vis[p][c]=ch[p][c]; fail[ch[p][c]]=p; q.push(vis[p][c]); } else vis[p][c]=p; } while(!q.empty()){ p=q.front(),q.pop(); for(int c=0;c<26;c++){ if(ch[p][c]){ vis[p][c]=ch[p][c]; fail[ch[p][c]]=vis[fail[p]][c]; q.push(vis[p][c]); } else vis[p][c]=vis[fail[p]][c]; } sum[p]=num[p]+sum[fail[p]]; } } void insert(char *s){ rt[++top]=++cnt;siz[top]=1; int len=strlen(s+1),p=rt[top],c; for(int i=1;i<=len;i++){ c=s[i]-'a'; if(!ch[p][c]) ch[p][c]=++cnt; p=ch[p][c]; } num[p]=1; while(siz[top-1]==siz[top]){ merge(rt[top-1],rt[top]); siz[top-1]+=siz[top];top--; } getfail(rt[top]); } int query(char *s){ int ans=0,len=strlen(s+1),p,c; for(int i=1;i<=top;i++){ p=rt[i]; for(int j=1;j<=len;j++){ c=s[j]-'a';p=vis[p][c]; ans+=sum[p]; } } return ans; } }A,B; int main() { scanf("%d",&n); int op; while(n--){ scanf("%d%s",&op,s+1); if(op==1) A.insert(s); if(op==2) B.insert(s); if(op==3) printf("%d\n",A.query(s)-B.query(s)); fflush(stdout); } return 0; }
2、bzoj2989 數列
離線做法:\(CDQ\) 分治。
線上做法:主席樹+二進位制分組。
暴力合併兩棵主席樹,別忘弄一個回收空間的垃圾桶 \(rub\)
然後我兩點多的時候第一次提交 \(RE\),本地測起來 \(MLE\),調了一個多小時,最後發現垃圾桶寫錯了。。。
\(Code\ Below:\)
#include <bits/stdc++.h> #define pii pair<int,int> #define mp make_pair using namespace std; const int maxn=200000+10; const int lim=100000; const int inf=0x3f3f3f3f; int n,q,a[maxn],rt[20][maxn],siz[20],top; int L[maxn<<5],R[maxn<<5],sum[maxn<<5],rub[maxn<<5],tot,cnt; vector<pii> v[20];bool vis[maxn<<5]; inline void read(int &x){ x=0;int f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} if(f==-1) x=-x; } inline void print(int x){ if(x<0){putchar('-');x=-x;} if(x==0) putchar('0'); static int sta[40],Top=0; while(x) sta[++Top]=x%10,x/=10; while(Top) putchar(sta[Top--]+'0'); putchar('\n'); } int newnode(){ vis[rub[tot]]=0; return rub[tot--]; } void update(int &now,int pre,int l,int r,int x){ now=newnode(); L[now]=L[pre];R[now]=R[pre];sum[now]=sum[pre]+1; if(l == r) return ; int mid=(l+r)>>1; if(x <= mid) update(L[now],L[pre],l,mid,x); else update(R[now],R[pre],mid+1,r,x); } int query(int u,int v,int Le,int Ri,int l,int r){ if(Le <= l && r <= Ri) return sum[v]-sum[u]; int mid=(l+r)>>1,ans=0; if(Le <= mid) ans+=query(L[u],L[v],Le,Ri,l,mid); if(Ri > mid) ans+=query(R[u],R[v],Le,Ri,mid+1,r); return ans; } void del(int x){ if(vis[x]) return ; vis[x]=1;rub[++tot]=x; if(L[x]) del(L[x]); if(R[x]) del(R[x]); sum[x]=L[x]=R[x]=0; } void build(int x){ for(int i=1;i<=siz[x];i++){ rt[x][i]=rt[x][i-1]; update(rt[x][i],rt[x][i],1,n+lim,v[x][i-1].second); } } void insert(int x,int y){ siz[++top]=1;v[top].push_back(mp(x,y));build(top); while(siz[top-1]==siz[top]){ for(int i=0;i<siz[top];i++) v[top-1].push_back(v[top][i]); sort(v[top-1].begin(),v[top-1].end()); v[top].clear(); for(int i=1;i<=siz[top];i++){ if(rt[top-1][i]) del(rt[top-1][i]); if(rt[top][i]) del(rt[top][i]); } siz[top-1]+=siz[top];build(--top); } } int ask(int x,int y,int k){ int l,r,ans=0; for(int i=1;i<=top;i++){ l=upper_bound(v[i].begin(),v[i].end(),mp(x-k,0))-v[i].begin(); r=upper_bound(v[i].begin(),v[i].end(),mp(x+k,inf))-v[i].begin(); if(l<=r) ans+=query(rt[i][l],rt[i][r],max(1,y-k),min(n+lim,y+k),1,n+lim); } return ans; } int main() { read(n),read(q); for(int i=1;i<=200000*32;i++) rub[++tot]=i,vis[i]=1; for(int i=1;i<=n;i++) read(a[i]),insert(a[i]-i+n,a[i]+i); char op[10];int x,k; while(q--){ scanf("%s",op+1);read(x),read(k); if(op[1]=='M') a[x]=k,insert(a[x]-x+n,a[x]+x); else print(ask(a[x]-x+n,a[x]+x,k)); } return 0; }