• [学习笔记]二进制分组


    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
    ",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('
    ');
    }
    
    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;
    }
    
  • 相关阅读:
    改变字符串里面多个颜色
    悬浮按钮
    改变一串字体的多个颜色
    iOS上如何让按钮文本左对齐问题
    Swift中的willSet与didSet
    Swift语法之 ---- ?和!区别
    UIButton文字的显示位置,字体的大小
    javaweb要点复习 jsp和servlet
    常量指针和指针常量
    判断括号序列的合法性
  • 原文地址:https://www.cnblogs.com/owencodeisking/p/10179707.html
Copyright © 2020-2023  润新知