zoukankan      html  css  js  c++  java
  • Jzoj5665 奥立卡的诗

    终于又遇到SAM的题了好好玩,而且就这道题让我弄清楚了广义SAM和Trie上SAM的区别

    其实两者是没有多少区别的,不过Trie上SAM可以更快

    关于Trie上SAM,是用bfs的方法来构建的,相比起广义SAM用dfs建少了一个深度之和的部分

    但是如果原题给的就是Trie那么就只能用bfs了,因为dfs会被卡成O(n^2) (考虑一个扫把)

    回到本题,简化一下式子发现这道题求的是不同子串的出现次数的平方和

    我们建出整个诗的广义SAM,对于一次询问,

    我们将一个串每个前缀对应的节点size都加一,树链剖分来维护所有节点的权值平方和

    让后就愉快的过了

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 600010
    #define LL long long
    #define mid (l+r>>1)
    #define ls l,mid,x<<1
    #define rs mid+1,r,x<<1|1
    using namespace std;
    char C[N]; LL ans=0;
    struct edge{ int v,nt; } G[N<<1];
    int n,m,cnt,clk,h[N],f[N],d[N],sz[N];
    int top[N],w[N],l[N],son[N],dx[N]; LL s2[N<<2],s[N<<2],t[N<<2],c[N<<2];
    inline void ps(int x){ 
    	s[x]=s[x<<1]+s[x<<1|1];
    	s2[x]=s2[x<<1]+s2[x<<1|1];
    }
    inline void adj(int x,int y){
    	G[++cnt]=(edge){y,h[x]}; h[x]=cnt;
    	G[++cnt]=(edge){x,h[y]}; h[y]=cnt;
    }
    inline void dfs(int x,int p){
    	f[x]=p; d[x]=d[p]+1; sz[x]=1;
    	for(int v,i=h[x];i;i=G[i].nt)
    		if(!d[v=G[i].v]){
    			dfs(v,x);
    			sz[x]+=sz[v];
    			if(sz[v]>sz[son[x]]) son[x]=v;
    		}
    }
    inline void dgs(int x,int p){
    	w[++clk]=x; l[x]=clk; top[x]=p;
    	if(son[x]) dgs(son[x],p);
    	for(int v,i=h[x];i;i=G[i].nt)
    		if(!top[v=G[i].v]) dgs(v,v);
    }
    inline void build(int l,int r,int x){
    	if(l==r){ c[x]=dx[w[l]]; return; }
    	build(ls);
    	build(rs);
    	c[x]=c[x<<1]+c[x<<1|1];
    }
    inline void pd(int x){
    	if(t[x]){
    		t[x<<1]+=t[x];
    		t[x<<1|1]+=t[x];
    		s2[x<<1]+=t[x]*t[x]*c[x<<1]+2*t[x]*s[x<<1];
    		s2[x<<1|1]+=t[x]*t[x]*c[x<<1|1]+2*t[x]*s[x<<1|1];
    		s[x<<1]+=c[x<<1]*t[x];
    		s[x<<1|1]+=c[x<<1|1]*t[x];
    		t[x]=0;
    	}
    }
    inline void add(int l,int r,int x,int L,int R){
    	if(L<=l && r<=R){
    		s2[x]+=c[x]+2*s[x];
    		s[x]+=c[x]; t[x]++; return;
    	}
    	pd(x);
    	if(L<=mid) add(ls,L,R);
    	if(mid<R) add(rs,L,R);
    	ps(x);
    }
    inline void gLca(int x){
    	for(;x;x=f[top[x]])
    		add(1,n,1,l[top[x]],l[x]);
    }
    struct SAM{
    	int s[N][26],mx[N],f[N],cnt,lst;
    	SAM(){ cnt=lst=1; }
    	inline int extend(int c){
    		int p=lst,np=lst=++cnt,q,nq;
    		mx[np]=mx[p]+1;
    		for(;p&&!s[p][c];p=f[p]) s[p][c]=np;
    		if(!p) return f[np]=1;
    		q=s[p][c];
    		if(mx[q]==mx[p]+1) f[np]=q;
    		else{
    			nq=++cnt;
    			mx[nq]=mx[p]+1;
    			f[nq]=f[q]; f[q]=f[np]=nq;
    			memcpy(s[nq],s[q],26<<2);
    			for(;p&&s[p][c]==q;p=f[p]) s[p][c]=nq;
    		}
    	}
    	inline void Ex_extend(int c){
    		int p=lst,q=s[p][c],nq;
    		if(q){
    			if(mx[q]==mx[p]+1){ lst=q; }
    			else{
    				lst=nq=++cnt;
    				mx[nq]=mx[p]+1;
    				f[nq]=f[q]; f[q]=nq;
    				memcpy(s[nq],s[q],26<<2);
    				for(;p&&s[p][c]==q;p=f[p]) s[p][c]=nq;
    			}
    		} else extend(c);
    	}
    	inline void BT(){
    		for(int i=2;i<=cnt;++i){
    			adj(f[i],i);
    			dx[i]=mx[i]-mx[f[i]];
    		}
    	}
    } S;
    int main(){
    	freopen("poem.in","r",stdin);
    	freopen("poem.out","w",stdout);
    	scanf("%d",&n);
    	for(int j=0;n--;++j){
    		scanf("%s",C+j); S.lst=1;
    		for(;C[j];++j) S.Ex_extend(C[j]-'a');
    	}
    	n=S.cnt; S.BT(); dfs(1,0); dgs(1,1); build(1,n,1);
    	for(int x=1,j=0;C[j];++j){
    		x=1;
    		while(C[j]){
    			x=S.s[x][C[j]-'a'];
    			gLca(x); ++j;
    		}
    		printf("%lld
    ",s2[1]);
    	}
    }


  • 相关阅读:
    golang包引用解析
    解决vs code中golang插件依赖安装失败问题
    设计模式之策略模式
    设计模式之模板方法
    设计模式——面向对象设计原则
    设计模式——个人浅谈
    Sublime Text3配置Lua运行环境
    Ntrip协议使用流程及服务器实现架构
    python3解析库lxml
    python3爬虫之Urllib库(二)
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477104.html
Copyright © 2011-2022 走看看