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;
}