• 【bzoj5084】 hashit(广义SAM+set)


    题面

    传送门

    题解

    后缀平衡树是个啥啊我不会啊……

    那么我们来考虑一下(SAM)的做法好了

    不难发现它的本义是要我们维护一棵(trie)树,并求出(trie)树上每一个节点到根的这段串的不同子串个数,而显然一个串的不同子串个数就是它的(SAM)上每一个节点的(len[p]-len[fa[p]])之和

    那么我们对这个(trie)建一个广义(SAM),这个(SAM)一定包含每一个路径的(SAM)

    我们对每一个这棵(trie)上的每一个节点记录一个(pos),表示这个节点插入在(SAM)上的哪一个位置,然后把(SAM)(parent)树记录一下(dfs)

    那么操作可以看做是在(parent)树上插入和删除节点,以插入为例,我们可以直接加上(p)到根节点的(len),但是这样有可能会算多,于是我们要减去(p)的前驱(以(dfs)序为顺序排列)和(p)(LCA)(len),以及和它的后继的(LCA)(len)。但是这样可能又减多了,所以还需要加上它的前驱和后继的(LCA)(len)

    然后没有然后了

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define ll long long
    #define IT set<int>::iterator
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(char *s){
    	R int len=0;R char ch;while(((ch=getc())>'z'||ch<'a')&&ch!='-');
    	for(s[++len]=ch;(ch=getc())>='a'&&ch<='z'||ch=='-';s[++len]=ch);
    	return s[len+1]='',len;
    }
    char sr[1<<21],z[20];int C=-1,Z=0;
    inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    void print(R ll x){
        if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]='
    ';
    }
    const int N=2e5+5;
    struct eg{int v,nx;}e[N<<1];int head[N],tot;
    inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    char t[N];int l[N],ch[N][26],fa[N],pos[N],st[N],dep[N],dfn[N],top[N],sz[N],son[N],rk[N];
    int las=1,cnt=1,n,tim;set<int> s;ll res;
    void ins(int c,int p=las){
    	if(ch[p][c]){
    		int q=ch[p][c];
    		if(l[q]==l[p]+1)las=q;
    		else{
    			int nq=las=++cnt;l[nq]=l[p]+1;
    			memcpy(ch[nq],ch[q],4*26);
    			fa[nq]=fa[q],fa[q]=nq;
    			for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
    		}
    	}else{
    		int np=las=++cnt;l[np]=l[p]+1;
    		for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
    		if(!p)fa[np]=1;
    		else{
    			int q=ch[p][c];
    			if(l[q]==l[p]+1)fa[np]=q;
    			else{
    				int nq=++cnt;l[nq]=l[p]+1;
    				memcpy(ch[nq],ch[q],4*26);
    				fa[nq]=fa[q],fa[q]=fa[np]=nq;
    				for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
    			}
    		}
    	}
    }
    void dfs1(int u){
    	sz[u]=1,dep[u]=dep[fa[u]]+1;
    	go(u){
    		dfs1(v),sz[u]+=sz[v];
    		sz[v]>sz[son[u]]?son[u]=v:0;
    	}
    }
    void dfs2(int u,int t){
    	top[u]=t,rk[dfn[u]=++tim]=u;
    	if(!son[u])return;
    	dfs2(son[u],t);
    	go(u)if(!top[v])dfs2(v,v);
    }
    int LCA(int u,int v){
    	while(top[u]!=top[v]){
    		dep[top[u]]<dep[top[v]]?(swap(u,v),0):0;
    		u=fa[top[u]];
    	}return dep[u]<dep[v]?u:v;
    }
    void update(int u,int op){
    	if(op==1)s.insert(u);
    	IT itl,itr,it;itl=itr=it=s.find(u);
    	res+=op*l[rk[u]];
    	if(itl!=s.begin())--itl,res-=op*l[LCA(rk[u],rk[*itl])];
    	if(itr!=--s.end())++itr,res-=op*l[LCA(rk[u],rk[*itr])];
    	if(itl!=it&&itr!=it)res+=op*l[LCA(rk[*itl],rk[*itr])];
    	if(op==-1)s.erase(u);
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	n=read(t);
    	st[0]=1;
    	for(R int i=1,top=0;i<=n;++i)if(t[i]=='-')--top;
    	else las=st[top],ins(t[i]-'a'),pos[i]=st[++top]=las;
    	fp(i,2,cnt)add(fa[i],i);
    	dfs1(1),dfs2(1,1);
    	for(R int i=1,top=0;i<=n;++i){
    		if(t[i]=='-')update(dfn[pos[st[top--]]],-1);
    		else update(dfn[pos[st[++top]=i]],1);
    		print(res);
    	}
    	return Ot(),0;
    }
    
  • 相关阅读:
    【Thinkphp教程】URL路由功能解析
    MYSQL 错误#145解决方法
    【Thinkphp教程】空模块
    【Thinkphp教程】 如何进行模块分组
    mySQL中删除unique key的语法
    使用php让浏览器刷新
    Spring+Jpa整合的过程中遇到的一个问题。。。纠结了我半天。。。
    关于mule studio的应用
    解决eclipse和myeclipse不能编译项目的问题
    ajax fileupload上传组件的使用感悟
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10582931.html
Copyright © 2020-2023  润新知