P4770 [NOI2018]你的名字 [后缀自动机,线段树合并]

对长串做个后缀自动机上线段树合并,然后你对每个短串搞个SAM在长串后缀自动机上跑。

答案就是 \(\sum \max(0, len_i - max(len_fa_i, endmax_{pos_i}))\)
\(pos_i\) 指的是 \(i\) 节点对应原字符串的位置。

// clang-format off
// powered by c++11
// by Isaunoya
#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define Rep(i,x,y) for(register int i=(x);i>=(y);--i)
using namespace std;
using db=double;
using ll=long long;
using uint=unsigned int;
using ull=unsigned long long;
using pii=pair<int,int>;
#define Tp template
#define fir first
#define sec second
Tp<class T>void cmax(T&x,const T&y) {
		if(x<y)x=y;
}
Tp<class T>void cmin(T&x,const T&y) {
		if(x>y)x=y;
}
#define all(v) v.begin(),v.end()
#define sz(v) ((int)v.size())
#define pb emplace_back
Tp<class T>void sort(vector<T>&v) {
		sort(all(v));
}
Tp<class T>void reverse(vector<T>&v) {
		reverse(all(v));
}
Tp<class T>void unique(vector<T>&v) {
		sort(all(v)),v.erase(unique(all(v)),v.end());
}
inline void reverse(string&s) {
	reverse(s.begin(),s.end());
}
const int SZ=1<<23|233;
struct FILEIN {
	char qwq[SZ],*S=qwq,*T=qwq,ch;
#ifdef __WIN64
#define GETC getchar
#else
	inline char GETC() {
		return(S==T)&&(T=(S=qwq)+fread(qwq,1,SZ,stdin),S==T)?EOF:*S++;
	}
#endif
	inline FILEIN&operator>>(char&c) {
		while(isspace(c=GETC()));
		return*this;
	} inline FILEIN&operator>>(string&s) {
		s.clear();
		while(isspace(ch=GETC()));
		if(!~ch)return*this;
		s=ch;
		while(!isspace(ch=GETC())&&~ch)s+=ch;
		return*this;
	}
	inline FILEIN&operator>>(char*str) {
		char*cur=str;
		while(*cur)*cur++=0;
		cur=str;
		while(isspace(ch=GETC()));
		if(!~ch)return*this;
		*cur=ch;
		while(!isspace(ch=GETC())&&~ch)*++cur=ch;
		*++cur=0;
		return*this;
	}
	Tp<class T>inline void read(T&x) {
			bool f=0;
			while((ch=GETC())<48&&~ch)f^=(ch==45);
			x=~ch?(ch^48):0;
			while((ch=GETC())>47)x=x*10+(ch^48);
			x=f?-x:x;
	}
	inline FILEIN&operator>>(int&x) {
		return read(x),*this;
	} inline FILEIN&operator>>(ll&x) {
		return read(x),*this;
	} inline FILEIN&operator>>(uint&x) {
		return read(x),*this;
	} inline FILEIN&operator>>(ull&x) {
		return read(x),*this;
	}
	inline FILEIN&operator>>(double&x) {
		read(x);
		bool f=x<0;
		x=f?-x:x;
		if(ch^'.')return*this;
		double d=0.1;
		while((ch=GETC())>47)x+=d*(ch^48),d*=.1;
		return x=f?-x:x,*this;
	}
} in;
struct FILEOUT {
	const static int LIMIT=1<<22;
	char quq[SZ],ST[233];
	int sz,O,pw[233];
	FILEOUT() {
		set(7);
		rep(i,pw[0]=1,9)pw[i]=pw[i-1]*10;
	}~FILEOUT() {
		flush();
	}
	inline void flush() {
		fwrite(quq,1,O,stdout),fflush(stdout),O=0;
	}
	inline FILEOUT&operator<<(char c) {
		return quq[O++]=c,*this;
	} inline FILEOUT&operator<<(string str) {
		if(O>LIMIT)flush();
		for(char c:str)quq[O++]=c;
		return*this;
	}
	inline FILEOUT&operator<<(char*str) {
		if(O>LIMIT)flush();
		char*cur=str;
		while(*cur)quq[O++]=(*cur++);
		return*this;
	}
	Tp<class T>void write(T x) {
			if(O>LIMIT)flush();
			if(x<0) {
				quq[O++]=45;
				x=-x;
			}
			do {
				ST[++sz]=x%10^48;
				x/=10;
			} while(x);
			while(sz)quq[O++]=ST[sz--];
	}
	inline FILEOUT&operator<<(int x) {
		return write(x),*this;
	} inline FILEOUT&operator<<(ll x) {
		return write(x),*this;
	} inline FILEOUT&operator<<(uint x) {
		return write(x),*this;
	} inline FILEOUT&operator<<(ull x) {
		return write(x),*this;
	}
	int len,lft,rig;
	void set(int l) {
		len=l;
	} inline FILEOUT&operator<<(double x) {
		bool f=x<0;
		x=f?-x:x,lft=x,rig=1.*(x-lft)*pw[len];
		return write(f?-lft:lft),quq[O++]='.',write(rig),*this;
	}
} out;
#define int long long
struct Math {
	vector<int>fac,inv;
	int mod;
	void set(int n,int Mod) {
		fac.resize(n+1),inv.resize(n+1),mod=Mod;
		rep(i,fac[0]=1,n)fac[i]=fac[i-1]*i%mod;
		inv[n]=qpow(fac[n],mod-2);
		Rep(i,n-1,0)inv[i]=inv[i+1]*(i+1)%mod;
	}
	int qpow(int x,int y) {
		int ans=1;
		for(; y; y>>=1,x=x*x%mod)if(y&1)ans=ans*x%mod;
		return ans;
	} int C(int n,int m) {
		if(n<0||m<0||n<m)return 0;
		return fac[n]*inv[m]%mod*inv[n-m]%mod;
	}
	int gcd(int x,int y) {
		return!y?x:gcd(y,x%y);
	} int lcm(int x,int y) {
		return x*y/gcd(x,y);
	}
} math;
// clang-format on

const int maxn = 1e6 + 61;
char s[maxn], t[maxn];

int q, n, m;
int rt[maxn];
struct SegMentTree {
  int ls[maxn << 5], rs[maxn << 5], cnt;

  SegMentTree() { cnt = 0; }

  void upd(int& p, int l, int r, int x) {
    if (!p) p = ++cnt;
    if (l == r) return;
    int mid = l + r >> 1;
    if (x <= mid)
      upd(ls[p], l, mid, x);
    else
      upd(rs[p], mid + 1, r, x);
  }

  int merge(int x, int y) {
    if (!x || !y) return x | y;
    int p = ++cnt;
    ls[p] = merge(ls[x], ls[y]);
    rs[p] = merge(rs[x], rs[y]);
    return p;
  }

  int qry(int p, int a, int b, int l, int r) {
    if (!p) return 0;
    if (a <= l && r <= b) return 1;
    int mid = l + r >> 1;
    if (a <= mid && qry(ls[p], a, b, l, mid)) return 1;
    if (b > mid && qry(rs[p], a, b, mid + 1, r)) return 1;
    return 0;
  }
} smt;

struct Suffix_Auto_Maton {
  int las, cnt;
  int ch[maxn][26], fa[maxn], len[maxn], pos[maxn];

  Suffix_Auto_Maton() { las = cnt = 1; }

  void clear() {
    rep(i, 1, cnt) {
      fa[i] = len[i] = pos[i] = 0;
      memset(ch[i], 0, sizeof(ch[i]));
    }
    las = cnt = 1;
  }

  void ins(int c, int id) {
    int p = las, np = las = ++cnt;
    len[np] = len[p] + 1, pos[np] = id;
    for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
    if (!p) {
      fa[np] = 1;
    } else {
      int q = ch[p][c];
      if (len[q] == len[p] + 1) {
        fa[np] = q;
      } else {
        int nq = ++cnt;
        pos[nq] = pos[q];
        memcpy(ch[nq], ch[q], sizeof(ch[q]));
        len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
        for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
      }
    }
  }
} sam, sam2;

vector<int> g[maxn];

void dfs(int u) {
  for (int v : g[u]) {
    dfs(v);
    rt[u] = smt.merge(rt[u], rt[v]);
  }
}

int match[maxn];
void getmatch(int l, int r) {
  int now = 1, nowl = 0;
  rep(i, 1, m) {
    while (233) {
      if (sam.ch[now][s[i] - 'a'] && smt.qry(rt[sam.ch[now][s[i] - 'a']], l + nowl, r, 1, n)) {
        now = sam.ch[now][s[i] - 'a'], nowl++;
        break;
      }
      if (!nowl) break;
      if (--nowl == sam.len[sam.fa[now]]) now = sam.fa[now];
    }
    match[i] = nowl;
  }
}

signed main() {
  // code begin.
  scanf("%s", s + 1), n = strlen(s + 1), sam.clear();
  rep(i, 1, n) 
		sam.ins(s[i] - 'a', i), smt.upd(rt[sam.las], 1, n, i);
  rep(i, 2, sam.cnt) 
		g[sam.fa[i]].pb(i);
  dfs(1);
  int _;
  scanf("%lld", &_);
  while (_--) {
    scanf("%s", s + 1);
    m = strlen(s + 1);
    int l, r;
    scanf("%lld%lld", &l, &r);
    sam2.clear();
    rep(i, 1, m) 
			sam2.ins(s[i] - 'a', i);
    getmatch(l, r);
    int ans = 0;
    rep(i, 2, sam2.cnt) 
			ans += max(0ll, sam2.len[i] - max(match[sam2.pos[i]], sam2.len[sam2.fa[i]]));
    printf("%lld\n", ans);
  }
  return 0;
  // code end.
}
posted @ 2020-03-25 19:36  _Isaunoya  阅读(141)  评论(0编辑  收藏  举报