zoukankan      html  css  js  c++  java
  • [HAOI2017]供给侧改革

    题目

    这道题我们其实就是利用了一棵后缀树

    由于字符串是随机的,所以这个后缀树的树高是(log)的,基于树高的算法是能过的

    我们考虑后缀树上的两个节点的(lca)就是这两个节点所代表的后缀的(lcp)

    我们可以把询问按照右端点离线,每次都暴力跳这个在后缀树上暴力跳父亲

    我们维护一下后缀树上子树里的最大值,这样我们就可以维护出对于每一种(lcp)出现最靠后的位置在哪里了

    对于每次询问我们扫一遍这些个(lcp)就好了

    至于如何建一棵后缀树,自然是把原串反着建一个SAM啊

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    const int maxn=2e5+5;
    struct Ask{int l,r,rk;}q[maxn>>1];
    int cnt=1,lst=1,len[maxn],son[maxn][2],fa[maxn];
    int pos[maxn>>1],lcp[maxn>>1],mx[maxn],g[maxn>>1],h[maxn>>1];
    int n,m,T;LL Ans[maxn>>1];char S[maxn>>1];
    inline int cmp(Ask A,Ask B) {return A.r<B.r;}
    inline void Extend(int c,int o) {
    	int p=++cnt,f=lst;lst=p;
    	len[p]=len[f]+1,pos[o]=p;
    	while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    	if(!f) {fa[p]=1;return;}
    	int x=son[f][c];
    	if(len[f]+1==len[x]) {fa[p]=x;return;}
    	int y=++cnt;
    	len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
    	son[y][0]=son[x][0],son[y][1]=son[x][1];
    	while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
    }
    inline void ins(int i) {
    	int x=pos[i];
    	while(x) {
    		lcp[len[x]]=max(lcp[len[x]],mx[x]);
    		if(lcp[len[x]]) T=max(T,len[x]);
    		mx[x]=max(mx[x],i);x=fa[x];
    	}
    }
    inline void calc(int j) {
    	int t=q[j].r-1,tmp=0;
    	LL ans=0;
    	for(re int i=1;i<=T;++i) 
    	if(lcp[i]) {
    		while(lcp[i]>=g[tmp]&&tmp) tmp--;
    		g[++tmp]=lcp[i],h[tmp]=i;
    	}
    	g[tmp+1]=0;
    	for(re int i=2;i<=tmp+1;i++) {
    		if(g[i]<q[j].l) {
    			ans+=(g[i-1]-q[j].l+1)*h[i-1];
    			break;
    		}
    		ans+=(g[i-1]-g[i])*h[i-1];
    	}
    	Ans[q[j].rk]=ans;
    }
    int main() {
    	n=read(),m=read();scanf("%s",S+1);
    	for(re int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].rk=i;
    	for(re int i=n;i;--i) Extend(S[i]-'0',i);
    	std::sort(q+1,q+m+1,cmp);ins(1);int tot=1;
    	for(re int i=2;i<=n;i++) {
    		ins(i);
    		while(q[tot].r==i) calc(tot++);
    	}
    	for(re int i=1;i<=m;i++) printf("%lld
    ",Ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    LeetCode: Trapping Rain Water
    LeetCode: Text Justification
    LeetCode: Unique Paths
    LeetCode: Unique Binary Search Trees
    向Google、Yahoo!和百度提交Sitemap网站地图
    Paypal IPN&PDT变量列表
    SQL查询和删除重复字段的内容
    [C#]基于.net技术的 Rss 订阅开发
    验证码识别流程
    c# string.Format 格式化日期
  • 原文地址:https://www.cnblogs.com/asuldb/p/10792291.html
Copyright © 2011-2022 走看看