[学习笔记]二进制分组

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;
}
posted @ 2018-12-26 16:08  Owen_codeisking  阅读(1032)  评论(0)    收藏  举报