zoukankan      html  css  js  c++  java
  • 【洛谷6292】区间本质不同子串个数(后缀自动机+LCT)

    点此看题面

    大致题意: 给定一个字符串,求区间本质不同的子串个数。

    类似题目

    有一道题目和这题很像:【LOJ6041】「雅礼集训 2017 Day7」事情的相似度

    二者都是离线+(LCT)维护(parent)树+树状数组维护信息,套路基本一样。

    离线

    首先我们把询问按右端点排序。

    这样就相当于只要不断在右边加入字符,然后维护每个左端点的答案。

    后缀自动机

    考虑求全局本质不同子串,显然就是一道后缀自动机智障题。

    但由于限定了区间,且根据我们的转化只要维护每个左端点的答案,那么我们可以考虑记录每个子串最后一次出现的位置

    然后就会发现,每次加入第(i)个新字符,相当于有(i)个子串最后一次出现的位置都变成了(i),也就是([1,i],[2,i],...,[i,i])

    考虑本质不同子串的计算方式,发现其实就是对于(1sim i)的每个左端点答案加(1)。(注意最后求答案是求([l,r])答案的总和,这里相当于是做了个差分)

    当然,我们还要除去这些子串原先的贡献,这就略有些麻烦了。

    (LCT)

    众所周知,(SAM)(parent)树是一棵树,而([1,i],[2,i],...,[i,i])这些子串等同于前缀(i)的所有后缀,也就是前缀(i)所对应节点在(parent)树上到根的路径

    每次操作相当于把一个节点到根的路径最后出现的位置全部修改为(i),也就是染成一个之前从未出现过的颜色。

    于是自然而然想到这样一道题:【BZOJ4817】[SDOI2017] 树点涂色。我们可以用(LCT)的每一棵(Splay)维护一条颜色相同的链。

    每次我们(Access)的时候,减去这棵(Splay)中节点原先的贡献,这道题就做完了。

    树状数组

    这道题需要区间修改、区间查询,而我又懒得写线段树了,就学()了一下树状数组的进阶写法。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define M 200000
    #define LL long long
    using namespace std;
    int n,p[N+5];char s[N+5];LL ans[M+5];typedef pair<int,int> Pr;vector<Pr> q[N+5];
    class SuffixAutomation//后缀自动机
    {
    	private:
    		int lst;struct node {int L,F,S[30];}O[2*N+5];
    	public:
    		int Nt;I SuffixAutomation() {Nt=lst=1;}
    		I int operator [] (CI x) {return O[x].F;}I int operator () (CI x) {return O[x].L;}
    		I int Ins(CI x)//返回节点对应编号
    		{
    			RI p=lst,o=lst=++Nt;O[o].L=O[p].L+1;
    			W(p&&!O[p].S[x]) O[p].S[x]=o,p=O[p].F;if(!p) return O[o].F=1,o;
    			RI q=O[p].S[x];if(O[p].L+1==O[q].L) return O[o].F=q,o;
    			RI k=++Nt;(O[k]=O[q]).L=O[p].L+1,O[q].F=O[o].F=k;
    			W(p&&O[p].S[x]==q) O[p].S[x]=k,p=O[p].F;return o;
    		}
    }SAM;
    class TreeArray//区间修改+区间查询 树状数组
    {
    	private:
    		LL a[N+5],b[N+5];I void U(RI x,CI v) {LL t=1LL*v*(x-1);W(x<=n) a[x]+=v,b[x]+=t,x+=x&-x;}
    		I LL Q(CI x) {RI i=x;LL t1=0,t2=0;W(i) t1+=a[i],t2+=b[i],i^=i&-i;return t1*x-t2;}
    	public:
    		I void U(CI l,CI r,CI v) {U(l,v),U(r+1,-v);}I LL Q(CI l,CI r) {return Q(r)-Q(l-1);}
    }T;
    class LinkCutTree//LCT
    {
    	private:
    		#define PD(x) O[x].G&&(Upt(O[x].S[0],O[x].G),Upt(O[x].S[1],O[x].G),O[x].G=0)
    		#define Upt(x,v) (O[x].V=O[x].G=v)
    		#define IR(x) (O[O[x].F].S[0]^x&&O[O[x].F].S[1]^x)
    		#define Wh(x) (O[O[x].F].S[1]==x)
    		#define Co(x,y,d) (O[O[x].F=y].S[d]=x)
    		int St[2*N+5];struct node {int V,G,F,S[2];}O[2*N+5];
    		I void Ro(CI x)
    		{
    			RI f=O[x].F,p=O[f].F,d=Wh(x);!IR(f)&&(O[p].S[Wh(f)]=x),O[x].F=p,
    			Co(O[x].S[d^1],f,d),Co(f,x,d^1);
    		}
    		I void S(CI x)
    		{
    			RI f=x,T=0;W(St[++T]=f,!IR(f)) f=O[f].F;W(T) PD(St[T]),--T;
    			W(!IR(x)) f=O[x].F,!IR(f)&&(Ro(Wh(x)^Wh(f)?x:f),0),Ro(x);
    		}
    	public:
    		I void Init() {for(RI i=1;i<=SAM.Nt;++i) O[i].F=SAM[i];}//建树
    		I void Ac(RI x,CI id)//Access染色
    		{
    			RI y=0;for(RI l,r;x;x=O[y=x].F) S(x),l=SAM(O[x].F)+1,r=SAM(x),//对应的子串长度
    				O[x].V&&(T.U(O[x].V-r+1,O[x].V-l+1,-1),0),O[x].S[1]=y;T.U(1,id,1),Upt(y,id);//清空原贡献,最后加上新贡献
    		}
    }LCT;
    int main()
    {
    	RI Qt,i,x,y;for(scanf("%s",s+1),n=strlen(s+1),i=1;i<=n;++i) p[i]=SAM.Ins(s[i]&31);//初始化建后缀自动机
    	for(scanf("%d",&Qt),i=1;i<=Qt;++i) scanf("%d%d",&x,&y),q[y].push_back(make_pair(i,x));//离线
    	RI j,s;for(LCT.Init(),i=1;i<=n;++i) for(LCT.Ac(p[i],i),//枚举右端点,每次更新LCT
    		j=0,s=q[i].size();j^s;++j) ans[q[i][j].first]=T.Q(q[i][j].second,i);//直接树状数组上询问左端点答案
    	for(i=1;i<=Qt;++i) printf("%lld
    ",ans[i]);return 0;
    }
    
  • 相关阅读:
    toggle()
    !important
    js 实现向下滑动页面时遇顶固定
    layui多文件选择之后自动上传
    position:fixed和z-index:1
    转:jquery 智能浮动定位smartFloat
    转:DATA URL简介及DATA URL的利弊
    年,月 ,季节 下拉框
    左连接与右连接,外连接与内连接
    git 恢复删去的东西, 以及在本地建个仓库,让远程也有这个仓库
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu6292.html
Copyright © 2011-2022 走看看