zoukankan      html  css  js  c++  java
  • 区间子串个数

    被jz姐姐欺负了之后去学了一下这个东西

    参考资料:陈江伦18年集训队论文《《后缀树结点数》命题报告及一类区间问题的优化》

    给定一个串(s)(q)次询问(s[l,r])的本质不同的子串个数

    sol1

    考虑离线,把所有的询问都给存到右端点上,建好(SAM)

    先考虑暴力,每一次右端点从(r-1)移到(r)时,记(id[r])表示在(SAM)上对应的节点,(end[p])(SAM)上的节点(p)当前最后一次出现的位置。对于每一个子串,我们只需要关心它最后一次出现的位置就行了。我们在线段树上每个点记录位于该点的合法的子串的左端点个数,那么每一次只要区间查询就行了

    对于(id[r])到根节点上的每个节点(p),它的长度是(l[fa[p]]+1)(l[p]),如果(end[p])不为(0),那么我们把([end[p]-l[p]+1,end[p]-l[fa[p]]])区间减一,最后再把([1,r])区间加一,然后就可以直接区间查询了

    我们发现一件事,如果某一次(fa[p])的更新来自(p)的子树,下一次(fa[p])更新的时候,更新的节点依然来自(p)的子树,那么这一次我们就可以把(fa[p])(p)放在一起考虑了

    然后我们发现这个东西就是(LCT)的一次(access)操作,那么用(LCT)维护就行了,复杂度(O(nlog^2 n))

    sol2

    然而(LCT)对于曲明这种从不背板选手不是很友好,曲明完全没有自信可以在考场上码对,于是自己(yy)了一下laofu论文里说的另一种树上启发式合并的方法

    我们发现,对于一个点,它儿子链的虚实切换次数是和轻儿子个数是同一个级别的,所以所有点的儿子链切换次数是(O(nlog n))(这也可以用来证明(LCT)(access)次数)

    我们考虑用dsu on tree来优化,对于每个点(u),把它的子树里所有的(endpos)都取出来,那么可以认为,(u)的实链会一直指向重儿子,而轻儿子(access)的时候会产生两个断点

    那么我们遍历轻儿子里所有的(endpos),对于每个(endpos),记为(p),找到(u)的子树中它的前驱(Pre),那么在(p)进行(access)的时候,(u)这个节点处在以(Pre)为端点的实链上,那么我们只要把这个记录下来,就可以在扫到(p)的时候再去更改。同理如果(p)的后继是(suf),那么(suf)(access)的时候需要更改此时处于(p)为端点的实链上的(u)。只要把所有的这样的操作都记录下来就行了

    这样的话,当我们扫到某个(p),我们把它的所有操作按需要更改的节点的长度排序,同时根据这个需要更改的节点处于哪个端点的实链上改一下就行了

    复杂度(O(nlog^2 n)),跑得比上面那个慢一丢丢(可能是我写萎了,如果又发现哪里可以优化的可以在下面嘲讽曲明)

    但是对于从来码不对LCT的曲明来说要好写不少

    代码1

    //2019.11.5 by ljz
    //#pragma GCC optimize(2)
    //email 573902690@qq.com
    //if you find any bug in my code
    //please tell me
    #include<bits/stdc++.h>
    //#include<ext/pb_ds/tree_policy.hpp>
    //#include<ext/pb_ds/assoc_container.hpp>
    using namespace std;
    //using namespace __gnu_pbds;
    //using namespace __gnu_cxx;
    #define res register int
    #define LL long long
    #define inf 0x3f3f3f3f
    #define INF 0x3f3f3f3f3f3f3f
    #define unl __int128
    #define eps 1e-9
    #define RG register
    #define db double
    //#define pc(x) __builtin_popcount(x)
    #define ctz(x) __builtin_ctz(x)
    #define pc(x) __builtin_popcountll(x)
    typedef pair<int,int> Pair;
    typedef pair<int,int> pi;
    #define mp make_pair
    #define fi first
    #define se second
    #define ull unsigned LL
    #define lowbit(x) (x&-x)
    #define gc getchar
    #include<bits/stdc++.h>
    #define pb emplace_back
    #define fp(i,a,b) for(RG int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(RG 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)
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    //template <class T>using Tree=tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
    //inline char gc() {
    //    static char buf[100000],*p1,*p2;
    //    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    //}
    //inline int read() {
    //    res s=0,ch=gc();
    //    while(ch<'0'||ch>'9')ch=gc();
    //    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc();
    //    return s;
    //}
    //char sr[1<<21],z[20];
    //int C=-1,Z=0;
    //inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    //inline void print(res 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]='
    ';
    //}
    inline int read() {
        res s=0,ch=gc(),w=1;
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=gc();}
        while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc();
        return s*w;
    }
    inline LL Read() {
        RG LL s=0;
        res ch=gc();
        while(ch<'0'||ch>'9')ch=gc();
        while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc();
        return s;
    }
    //inline LL Read() {
    //    RG LL s=0;
    //    res ch=gc(),w=1;
    //    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=gc();}
    //    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc();
    //    return s*w;
    //}
    //inline void write(RG unl x){
    //    if(x>10)write(x/10);
    //    putchar(int(x%10)+'0');
    //}
    inline void swap(res &x,res &y) {
        x^=y^=x^=y;
    }
    //mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    //clock_t start=clock();
    //inline void ck(){
    //    if(1.0*(clock()-start)/CLOCKS_PER_SEC>0.1)exit(0);
    //}
    const int kcz=1000000007;
    inline void add(res &x,const res &y){
        x+=y,x>=kcz?x-=kcz:(x<0?x+=kcz:1);
    }
    inline int Add(const res &x,const res &y){
        return x+y>=kcz?x+y-kcz:(x+y<0?x+y+kcz:x+y);
    }
    inline int mul(const res &x,const res &y){
        return int(1LL*x*y%kcz);
    }
    inline int mul(const res &x,const res &y,const res &d){
        return int(1LL*x*y/d%kcz);
    }
    inline int sqr(const res &x){
        return int(1LL*x*x%kcz);
    }
    inline int qpow(res x,res y){
        res ret=1;
        while(y){
            if(y&1)ret=mul(ret,x);
            x=mul(x,x),y>>=1;
        }
        return ret;
    }
    inline LL Qpow(RG LL x,res y){
        RG LL ret=1;
        while(y){
            if(y&1)ret*=x;
            x*=x,y>>=1;
        }
        return ret;
    }
    const int N=5e5+10;
    int n;char s[N];
    int pos[N];
    struct SAM{
    	struct Sam{
    		int vis[26],par,len,pos;
    	}sam[N<<1];
    	int las,rt,cnt;
    	SAM() {las=rt=cnt=1;}
    	inline void extend(const res &x,const res &id){
            res p=las,np=++cnt;
            las=np,sam[np].len=sam[p].len+1,pos[id]=las;
            for(;p&&!sam[p].vis[x];p=sam[p].par)sam[p].vis[x]=np;
            if(!p)sam[np].par=rt;
            else {
                res q=sam[p].vis[x];
                if(sam[q].len==sam[p].len+1)sam[np].par=q;
                else {
                    res nq=++cnt;
                    memcpy(sam[nq].vis,sam[q].vis,sizeof(sam[nq].vis));
                    sam[nq].len=sam[p].len+1;
                    sam[nq].par=sam[q].par;
                    sam[q].par=sam[np].par=nq;
                    for(;p&&sam[p].vis[x]==q;p=sam[p].par)sam[p].vis[x]=nq;
                }
            }
        }
    }A;
    typedef pair<int,int> Pair;
    #define mp make_pair
    #define fi first
    #define se second
    int q;
    LL ans[N];
    vector<Pair> vec[N];
    struct Seg{
    	LL sum[N<<2];
    	int add[N<<2],len[N<<2];
    	inline void pushup(const res &rt){
    		sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    	}
    	inline void change(const res &rt,const res &val){
    		sum[rt]+=1LL*val*len[rt],add[rt]+=val;
    	}
    	inline void pushdown(const res &rt){
    		if(!add[rt])return;
    		change(rt<<1,add[rt]),change(rt<<1|1,add[rt]),add[rt]=0;
    	}
    	void build(const res &rt,const res &l,const res &r){
    		len[rt]=r-l+1;
    		if(l==r)return;
    		res mid=(l+r)>>1;
    		build(rt<<1,l,mid),build(rt<<1|1,mid+1,r);
    	}
    	void modify(const res &rt,const res &l,const res &r,const res &L,const res &R,const res &val){
    		if(L>R)return;
    		if(L<=l&&r<=R){change(rt,val);return;}
    		pushdown(rt);
    		res mid=(l+r)>>1;
    		if(L<=mid)modify(rt<<1,l,mid,L,R,val);
    		if(R>mid)modify(rt<<1|1,mid+1,r,L,R,val);
    		pushup(rt);
    	}
    	LL query(const res &rt,const res &l,const res &r,const res &L,const res &R){
    		if(L>R)return 0;
    		if(L<=l&&r<=R)return sum[rt];
    		pushdown(rt);
    		res mid=(l+r)>>1;
    		LL ret=0;
    		if(L<=mid)ret+=query(rt<<1,l,mid,L,R);
    		if(R>mid)ret+=query(rt<<1|1,mid+1,r,L,R);
    		return ret;
    	}
    }B;
    inline int _max(RG int x,RG int y){return x>y?x:y;}
    inline int _min(RG int x,RG int y){return x<y?x:y;}
    inline void _swap(RG int &x,RG int &y){RG int t=x;x=y,y=t;}
    struct LCT{
    	struct Lct{
    		int son[2],sz,fa,mn,mx,mxlen,mnlen,col;
    		bool rev;
    	}tr[N];
    	inline void pushup(const res &x){
    		if(!x)return;
    		res ls=tr[x].son[0],rs=tr[x].son[1];
    		tr[x].sz=tr[ls].sz+tr[rs].sz+1;
    		tr[x].mx=_max(_max(tr[ls].mx,tr[rs].mx),tr[x].mxlen);
    		tr[x].mn=_min(_min(tr[ls].mn,tr[rs].mn),tr[x].mnlen);
    	}
    	inline void reversed(const res &x){
    		if(!x)return;
    		res &ls=tr[x].son[0],&rs=tr[x].son[1];
    		_swap(ls,rs),tr[x].rev^=1;
    	}
    	inline void pushdown(const res &x){
    		if(!x||!tr[x].rev)return;
    		res ls=tr[x].son[0],rs=tr[x].son[1];
    		reversed(ls),reversed(rs),tr[x].rev=0;
    	}
    	inline bool nroot(const res &x) {
        	return tr[tr[x].fa].son[0]==x||tr[tr[x].fa].son[1]==x;
    	}
    	inline void rotate(const res &x) {
        	res y=tr[x].fa,z=tr[y].fa,k=tr[y].son[1]==x,w=tr[x].son[k^1];
        	if(nroot(y))tr[z].son[tr[z].son[1]==y]=x;
        	tr[x].son[k^1]=y,tr[y].son[k]=w;
        	if(w)tr[w].fa=y;
        	tr[y].fa=x,tr[x].fa=z;
        	pushup(y);
    	}
    	int st[N];
    	inline void splay(const res &x) {
       	 	res i=x,s=0;
        	st[++s]=x;
        	while(nroot(i))st[++s]=i=tr[i].fa;
        	res t=tr[st[s]].col;
        	while(s)pushdown(st[s--]);
        	while(nroot(x)) {
            	res y=tr[x].fa,z=tr[y].fa;
            	if(nroot(y))rotate((tr[y].son[0]==x)^(tr[z].son[0]==y)?x:y);
            	rotate(x);
        	}
        	pushup(x);
        	tr[x].col=t;
    	}
    	inline void access(res x,const res &val){
    		res y;
    		for(y=0;x;x=tr[y=x].fa){
    			splay(x);
    			res Mn=0,Mx=A.sam[x].len;
    			if(tr[x].son[0])Mn=_max(tr[tr[x].son[0]].mn,1);
    			else Mn=A.sam[A.sam[x].par].len+1;
    			if(tr[x].col)B.modify(1,1,n,tr[x].col-Mx+1,tr[x].col-Mn+1,-1);
    			tr[tr[x].son[1]].col=tr[x].col,tr[x].son[1]=y,pushup(x);
    		}
    		tr[y].col=val,B.modify(1,1,n,val-tr[y].mx+1,val,1);
    	}
    	inline void calc(){
    		tr[0].mn=inf;
    		for(res i=1;i<=A.cnt;i++){
    			tr[i].sz=1,tr[i].fa=A.sam[i].par;
    			if(i==1)tr[i].mn=tr[i].mnlen=0;
    			else tr[i].mn=tr[i].mnlen=A.sam[A.sam[i].par].len+1;
    			tr[i].mx=tr[i].mxlen=A.sam[i].len;
    		}
    		for(res i=1;i<=n;i++){
    			access(pos[i],i);
    			for(res j=0,sz=vec[i].size();j<sz;j++)ans[vec[i][j].se]=B.query(1,1,n,vec[i][j].fi,i);
    		}
    	}
    }T;
    namespace MAIN{
    	void MAIN(){
    		scanf("%s",s+1),n=strlen(s+1);
    		fp(i,1,n)A.extend(s[i]-'a',i);
    		B.build(1,1,n);
    		scanf("%d",&q);
    		for(RG int i=1,l,r;i<=q;++i){
    			scanf("%d%d",&l,&r);
    			vec[r].pb(pi(l,i));
    		}
    		T.calc();
    		fp(i,1,q)printf("%lld
    ",ans[i]);
    	}
    }
    int main(){
        freopen("t.in","r",stdin);
        freopen("t.out","w",stdout);
    	MAIN::MAIN();
        return 0;
    }
    

    代码2

    //quming
    #include<bits/stdc++.h>
    #define R register
    #define fi first
    #define se second
    #define pb emplace_back
    #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)
    #define gg(u) for(int i=hc[u],v=E[i].v;i;i=E[i].nx,v=E[i].v)
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pi;
    const int N=5e5+5,M=N*10;
    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;}
    int n,m;char str[N];
    namespace BIT{
    	struct node;typedef node* ptr;
    	struct node{ptr lc,rc;ll s;int t;}e[N<<2],*rt,*pp=e;
    	void build(ptr &p,int l,int r){
    		p=++pp;if(l==r)return;
    		int mid=(l+r)>>1;
    		build(p->lc,l,mid),build(p->rc,mid+1,r);
    	}
    	void update(ptr p,int l,int r,int ql,int qr,int d){
    		p->s+=d*(qr-ql+1);if(ql<=l&&qr>=r)return p->t+=d,void();
    		int mid=(l+r)>>1;
    		if(qr<=mid)return update(p->lc,l,mid,ql,qr,d);
    		if(ql>mid)return update(p->rc,mid+1,r,ql,qr,d);
    		update(p->lc,l,mid,ql,mid,d),update(p->rc,mid+1,r,mid+1,qr,d);
    	}
    	ll query(ptr p,int l,int r,int ql,int qr,int d){
    		if(ql<=l&&qr>=r)return p->s+d*(qr-ql+1);
    		int mid=(l+r)>>1;d+=p->t;
    		if(qr<=mid)return query(p->lc,l,mid,ql,qr,d);
    		if(ql>mid)return query(p->rc,mid+1,r,ql,qr,d);
    		return query(p->lc,l,mid,ql,mid,d)+query(p->rc,mid+1,r,mid+1,qr,d);
    	}
    	inline ll query(R int l,R int r){return query(rt,1,n,l,r,0);}
    	inline void upd(R int l,R int r,R int d){update(rt,1,n,l,r,d);}
    	inline void build(){build(rt,1,n);}
    }
    //namespace BIT{
    //    //区间修改区间查询树状数组 
    //    ll d[N];int c[N];
    //    inline void chgd(R int x,R int v){for(;x<=n;x+=x&-x)d[x]+=v;}
    //    inline void chgc(R int x,R int v){for(;x<=n;x+=x&-x)c[x]+=v;}
    //    inline void upd(R int l,R int r,R int v){
    //        chgc(r+1,-v),chgd(r+1,-v*(r+1));
    //        if(l!=0)chgc(l,v),chgd(l,v*l);
    //    }
    //    inline int askc(R int x){R int res=0;for(;x;x-=x&-x)res+=c[x];return res;}
    //    inline ll askd(R int x){R ll res=0;for(;x;x-=x&-x)res+=d[x];return res;}
    //    inline ll query(R int l,R int r){
    //        R ll res=0;
    //        res+=1ll*(r+1)*askc(r)-askd(r);
    //        if(l>1)res-=1ll*l*askc(l-1)-askd(l-1);
    //        return res;
    //    }
    //}
    namespace ljz{
        int l[N],fa[N],ch[N][26],cnt=1,las=1;
        void ins(int c,int p=las){
            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],104);
                    fa[nq]=fa[q],fa[q]=fa[np]=nq;
                    for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
                }
            }
        }
        struct chg{int v,nx,w;}E[M];int hc[N],tc;
        inline void Add(R int u,R int v,R int w){E[++tc]={v,hc[u],w},hc[u]=tc;}
        int dfn[N],sz[N],son[N],id[N],pos[N],tim;
        set<int>s;typedef set<int>::iterator IT;
        void dfs1(int u){
            sz[u]=(id[u]!=0),son[u]=0;
            go(u){
                dfs1(v),sz[u]+=sz[v];
                if(sz[v]>sz[son[u]])son[u]=v;
            }
        }
        void inc(int u){if(id[u])s.insert(id[u]),dfn[id[u]]=tim;go(u)inc(v);}
        void get(int u,int sn,int rt){
    //        printf("%d %d %d
    ",u,sn,rt);
            if(id[u]){
                IT it=s.lower_bound(id[u]),itl=it;
                if(it!=s.begin()&&dfn[*--it]!=dfn[id[u]])Add(id[u],rt,*it);
                ++itl;
                if(itl!=s.end()&&dfn[*itl]!=dfn[id[u]])Add(*itl,rt,id[u]);
            }
            go(u)if(v!=sn)get(v,sn,rt);
        }
        void dfs2(int u){
    //        printf("%d
    ",u);
            go(u)if(v!=son[u])dfs2(v),s.clear();
            if(son[u])dfs2(son[u]);
            if(id[u])s.insert(id[u]),dfn[id[u]]=++tim;
            go(u)if(v!=son[u])++tim,inc(v);
            if(u!=1)get(u,son[u],u);
        }
        vector<pi>qr[N];ll ans[N];pi st[N];int top;
        inline bool cmp(const pi &a,const pi &b){return l[a.fi]>l[b.fi];}
        void MAIN(){
            scanf("%s%d",str+1,&m),n=strlen(str+1);
            BIT::build();
            fp(i,1,n)ins(str[i]-'a'),id[las]=i;
            fp(i,2,cnt)add(fa[i],i);
            dfs1(1),dfs2(1);
            for(R int i=1,l,r;i<=m;++i)scanf("%d%d",&l,&r),qr[r].pb(pi(l,i));
            fp(u,1,n){
                BIT::upd(1,u,1);
                top=0;
                gg(u)st[++top]=pi(E[i].v,E[i].w);
                st[top+1]=pi(0,0);
                sort(st+1,st+1+top,cmp);
                fp(i,1,top)if(l[st[i].fi]>l[st[i+1].fi]){
    //            	printf("%d %d")
                	BIT::upd(st[i].se-l[st[i].fi]+1,st[i].se-l[st[i+1].fi],-1);
    			}
                for(auto v:qr[u])ans[v.se]=BIT::query(v.fi,u);
            }
            fp(i,1,m)printf("%lld
    ",ans[i]);
        }
    }
    int main(){
        freopen("t.in","r",stdin);
        freopen("t.out","w",stdout);
        ljz::MAIN();
        return 0;
    }
    
  • 相关阅读:
    java去掉List中的重复值代码
    jquery 请求jsp传递json数据的方法
    jsp自定义标签分析
    jquery mouseout事件冒泡解决方法
    java split函数 对空的处理
    log4j使用感受
    mysql数据库主外键级联删除脚本RESTRICT --> CASCADE
    jquery 实现层级下拉框联动效果 代码
    JSP图片上传 公共工具类
    Apache和Nginx的对比
  • 原文地址:https://www.cnblogs.com/yuanquming/p/11803671.html
Copyright © 2011-2022 走看看