• [BZOJ3879]SvT


    Description

    (我并不想告诉你题目名字是什么鬼)

    有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n].

    现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.

    Input

    第一行两个正整数n,m,分别表示S的长度以及询问的次数.

    接下来一行有一个字符串S.

    接下来有m组询问,对于每一组询问,均按照以下格式在一行内给出:

    首先是一个整数t,表示共有多少个后缀.接下来t个整数分别表示t个后缀在字符串S中的出现位置.

    Output

    对于每一组询问,输出一行一个整数,表示该组询问的答案.由于答案可能很大,仅需要输出这个答案对于23333333333333333(一个巨大的质数)取模的余数.

    Sample Input

    7 3
    popoqqq
    1 4
    2 3 5
    4 1 2 5 6
    

    Sample Output

    0 
    0
    2
    

    Solution

    首先那个模数是没有用的....答案最大都不到那个模数。

    然后注意到两个后缀的(lcp)长度就是他们后缀树上的(lca)(dis),所以建出后缀树之后对于每组询问建一棵虚树,在树上暴力统计答案就好了。

    然后这题就真的码农了...

    我反正码了一个多小时...

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long 
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(ll x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(ll x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 1e6+10;
    
    int n,m;
    char s[maxn];
    int id[maxn],dis[maxn],dfn[maxn],cnt[maxn],sz[maxn];
    
    struct Suffix_Tree {
    	int head[maxn],tot,dfn_cnt,f[maxn][20],dep[maxn];
    	
    	struct edge{int to,nxt;}e[maxn<<1];
    
    	void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    	void ins(int u,int v) {add(u,v),add(v,u);}
    
    	void dfs(int x,int fa) {
    		dfn[x]=++dfn_cnt;f[x][0]=fa;dep[x]=dep[fa]+1;sz[x]=1;
    		for(int i=1;i<=18;i++) f[x][i]=f[f[x][i-1]][i-1];
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=fa) dfs(e[i].to,x),sz[x]+=sz[e[i].to];
    	}
    
    	int lca(int x,int y) {
    		if(dep[x]<dep[y]) swap(x,y);
    		for(int i=18;~i;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
    		if(x==y) return x;
    		for(int i=18;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    		return f[x][0];
    	}
    }T;
    
    struct Suffix_Automaton {
    	int lstp,qs,cnt;
    	int tr[maxn][26],par[maxn],ml[maxn];
    	
    	void clear() {lstp=qs=cnt=1;}
    
    	void append(int x,int v) {
    		int p=lstp,np=++cnt;ml[np]=ml[p]+1;id[v]=np;lstp=np;
    		for(;p&&tr[p][x]==0;p=par[p]) tr[p][x]=np;
    		if(!p) return par[np]=qs,void();
    		int q=tr[p][x];
    		if(ml[p]+1<ml[q]) {
    			int nq=++cnt;ml[nq]=ml[p]+1;
    			memcpy(tr[nq],tr[q],sizeof tr[nq]);
    			par[nq]=par[q],par[q]=par[np]=nq;
    			for(;p&&tr[p][x]==q;p=par[p]) tr[p][x]=nq;
    		} else par[np]=q;
    	}
    
    	void prepare() {
    		for(int i=2;i<=cnt;i++) T.ins(i,par[i]);
    		for(int i=1;i<=cnt;i++) dis[i]=ml[i];
    	}
    }sam;
    
    int cmp(int x,int y) {return dfn[x]<dfn[y];}
    
    struct Virtual_Tree {
    	ll ans;
    	int head[maxn],tot,in[maxn],sta[maxn],use[maxn],used,top;
    	
    	struct edge{int to,nxt;}e[maxn<<1];
    
    	void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    	void ins(int u,int v) {add(u,v),add(v,u);}
    
    	void dfs(int x,int fa) {
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=fa) {
    				dfs(e[i].to,x);
    				ans+=1ll*dis[x]*cnt[x]*cnt[e[i].to];
    				cnt[x]+=cnt[e[i].to];
    			}
    	}
    	
    	void solve() {
    		int k;read(k);
    		for(int i=1,x;i<=k;i++) read(x),in[i]=id[x],cnt[in[i]]=1;
    		sort(in+1,in+k+1,cmp);k=unique(in+1,in+k+1)-in-1;
    		sta[++top]=1;use[++used]=1;
    		for(int i=1;i<=k;i++) {
    			if(in[i]==1) continue;
    			int pre=-1,t=T.lca(sta[top],in[i]);
    			while(dfn[sta[top]]>dfn[t]&&dfn[sta[top]]<dfn[t]+sz[t]) {
    				if(pre!=-1) ins(sta[top],pre);pre=sta[top],top--;
    			}
    			if(pre!=-1) ins(pre,t);
    			if(sta[top]!=t) sta[++top]=t,use[++used]=t;
    			sta[++top]=in[i];use[++used]=in[i];
    		}
    		int pre=-1;
    		while(top) {if(pre!=-1) ins(sta[top],pre);pre=sta[top];top--;}
    		ans=0;dfs(1,0);write(ans);
    		for(int i=1,v;i<=used;i++) head[v=use[i]]=0,cnt[v]=0;
    		used=top=tot=0;
    	}
    }VT;
    
    int main() {
    	read(n),read(m);
    	scanf("%s",s+1);sam.clear();
    	for(int i=1;i<=n;i++) sam.append(s[n-i+1]-'a',n-i+1);
    	sam.prepare();T.dfs(1,0);
    	for(int i=1;i<=m;i++) VT.solve();
    	return 0;
    }
    
  • 相关阅读:
    VS远程调试项目,利用msvsmon
    web deploy发布网站各种问题
    IOS中UITabBar、UIDatePicker、Picker View控件练习(二)
    IOS中多视图应用视图切换
    IOS中多视图应用设置首界面
    Asp.net中Application Session Cookie ViewState Cache Hidden
    UI控件(scrollView、tableView)的基本使用
    UI错误集
    UI小项目之拳皇动画的实现(抽取加载图片和播放音乐的方法)
    UI控件(Label、ImageView、Button)的基本使用
  • 原文地址:https://www.cnblogs.com/hbyer/p/10469286.html
Copyright © 2020-2023  润新知