卧薪尝胆,厚积薄发。
      
    
            串
        
        
        Description:
给出字符串
$S,T$
,多次询问
$T$
的一个子串
$T[l:r]$
在
$S$
的所有循环同构串的长度 为
$k$
的前缀中出现过的字符串的数量。
$|S|,|T|,q\leqslant2\times10^5$
 
Solution:
首先把
$S$
倍长和
$T$
放在一起建立广义后缀自动机,那么我们每次询问就只要把
$T[l:r]$
在
$SAM$
上找到对应的位置回答询问,考虑答案是什么,我们可以把
$T[l:r]$
在
$S$
倍长的串中找出来,然后如果只考虑一个串,那么贡献应该是
$k-len(T[l:r])$
,但是由于两个串之间可能相交,那么贡献就是
$\min(k-len(T[l:r]),\Delta)$
,
$\Delta$
表示这个位置和上一个位置的差,如果只有一个节点的话,我们可以把所有的
$\Delta$
插入两个树状数组中,一个维护值,另一个维护个数,然后每次就可以在上面查询,如果有多个查询的话,我们可以把所有询问离线挂在点上,然后用树上启发式合并的做法把子节点插在树状数组中就可以了。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<set>
#include<vector>
#include<cctype>
#include<cstring>
using namespace std;
#define MAXN 800010
inline int rd()
{
	register int res = 0,f = 1;register char c = getchar();
	while(!isdigit(c)){if(c == '-')f = -1;c = getchar();}
	while(isdigit(c))res = (res << 1) + (res << 3) + c - '0',c = getchar();
	return res;
}
#pragma GCC optimaze(3)
int q;
char S[MAXN],T[MAXN];
int l1,l2;
namespace SAM
{
	struct node
	{
		int tr[26];
		int maxl,par,rig;
	}s[MAXN << 2];
	bool tag[MAXN << 2];
	int ptr = 1,root = 1,last = 1;
	int newnode(int l){int k = ++ptr;s[k].maxl = l;return k;}
	int pos[MAXN << 2];
	void extend(int k,int cur)
	{
		int p = last;
		if(s[p].tr[k])
		{
			int q = s[p].tr[k];
			if(s[p].maxl + 1 == s[q].maxl)last = q;
			else
			{
				int nq = newnode(s[p].maxl + 1);
				memcpy(s[nq].tr,s[q].tr,sizeof(s[q].tr));
				s[nq].par = s[q].par;s[q].par = nq;
				for(;p && s[p].tr[k] == q;p = s[p].par)s[p].tr[k] = nq;
				last = nq;
			}
		}
		else
		{
			int np = newnode(s[p].maxl + 1);tag[np] = true;
			for(;p && s[p].tr[k] == 0;p = s[p].par)s[p].tr[k] = np;
			if(p == 0)s[np].par = root;
			else
			{
				int q = s[p].tr[k];
				if(s[p].maxl + 1 == s[q].maxl)s[np].par = q;
				else
				{
					int nq = newnode(s[p].maxl + 1);
					memcpy(s[nq].tr,s[q].tr,sizeof(s[q].tr));
					s[nq].par = s[q].par;
					s[q].par = s[np].par = nq;
					for(;p && s[p].tr[k] == q;p = s[p].par)s[p].tr[k] = nq;
				}
			}
			last = np;
		}
		if(cur)s[last].rig = cur;
		return;
	}
	struct edge
	{
		int to,nxt;
	}e[MAXN << 2];
	int edgenum = 0;
	int lin[MAXN << 2] = {0};
	void add(int a,int b)
	{
		e[++edgenum] = (edge){b,lin[a]};lin[a] = edgenum;
		return;
	}
	void build()
	{
		for(int i = 2;i <= ptr;++i)add(s[i].par,i);
		return;
	}
	int f[MAXN << 2][20];
	void dfs(int k)
	{
		for(int i = 1;i <= 19;++i)f[k][i] = f[f[k][i - 1]][i - 1];
		for(int i = lin[k];i != 0;i = e[i].nxt)
		{
			f[e[i].to][0] = k;
			dfs(e[i].to);
		}
		return;
	}
	int getpos(int l,int r)
	{
		int cur = pos[r];
		for(int i = 19;i >= 0;--i)if(s[f[cur][i]].maxl >= r - l + 1)cur = f[cur][i];
		return cur;
	}
}
struct BIT
{
	int c1[MAXN << 2],c2[MAXN << 2];
	#define N (2 * l1)
	int lowbit(int x){return x & (-x);}
	void adds(int p,int x){++p;for(int i = p;i <= N;i += lowbit(i))c1[i] += x;return;}
	void addt(int p,int x){++p;for(int i = p;i <= N;i += lowbit(i))c2[i] += x;return;}
	int querys(int p){int res = 0;++p;for(int i = p;i >= 1;i -= lowbit(i))res += c1[i];return res;}
	int queryt(int p){int res = 0;++p;for(int i = p;i >= 1;i -= lowbit(i))res += c2[i];return res;}
}t;
#define iter set<int>::iterator
namespace QUERY
{
	struct query
	{
		int len,k,ans;
	}p[MAXN];
	vector<int> v[MAXN << 2];
	set<int> s;
	int judge = 0,crossx,crossy;
	int nowans;
	void change(int l,int r,int tag)
	{//cout << l << " " << r << " " << tag << endl;
		if(l < l1)return;
		if(l >= r)return;
		int k = r - l;
		t.adds(k,k * tag);
		t.addt(k,tag);
		nowans += k * tag;
		return;
	}
	int query(int k,int len)
	{//cout << "query " << k << " " << len << endl;
		int ans = nowans,val = k - len + 1;
		int q = t.querys(N) - t.querys(val),num = t.queryt(N) - t.queryt(val);
		ans = ans - q + num * val;//cout << q << " " << val << " " << num << endl;
		//cout << ans << " " << judge << " " << crossx << " " << crossy << endl;
		if(judge)
		{
			ans += crossy - l1;
			if(crossx + val - 1 < crossy)ans -= crossy - max(l1,crossx + val);
		}//cout << ans << endl;
		return ans;
	}
	void query(int k)
	{
		for(vector<int>::iterator it = v[k].begin();it != v[k].end();++it)
		{
			p[*it].ans = query(p[*it].k,p[*it].len);
		}
		return;
	}
	void insert(int val)
	{//cout << "insert " << val << endl;
		iter it = s.lower_bound(val);
		if(it != s.begin())
		{
			iter it_ = it;--it_;
			change(*it_,val,1);
			change(*it_,*it,-1);
		}
		change(val,*it,1);
		s.insert(val);
		it = s.lower_bound(l1);
		judge = 0;
		if(it != s.begin()){judge = 1;iter it_ = it;--it_;crossx = *it_;crossy = *it;}
		return;
	}
	void remove(int val)
	{//cout << "remove " << val << endl;
		s.erase(val);
		iter it = s.lower_bound(val);
		if(it != s.begin())
		{
			iter it_ = it;--it_;
			change(*it_,*it,1);
			change(*it_,val,-1);
		}
		change(val,*it,-1);
		it = s.lower_bound(l1);
		judge = 0;
		if(it != s.begin()){judge = 1;iter it_ = it;--it_;crossx = *it_;crossy = *it;}
		return;
	}
}
int dep[MAXN << 2],son[MAXN << 2],siz[MAXN << 2];
void dfs1(int k,int fa)
{
	using namespace SAM;
	siz[k] = 1;
	for(int i = lin[k];i != 0;i = e[i].nxt)
	{
		dfs1(e[i].to,k);
		siz[k] += siz[e[i].to];
		if(son[k] == 0 || siz[e[i].to] > siz[son[k]])son[k] = e[i].to;
	}
	return;
}
void add(int k)
{
	using namespace SAM;
	if(s[k].rig)QUERY::insert(s[k].rig);
	for(int i = lin[k];i != 0;i = e[i].nxt)add(e[i].to);
	return;
}
void del(int k)
{
	using namespace SAM;
	if(s[k].rig)QUERY::remove(s[k].rig);
	for(int i = lin[k];i != 0;i = e[i].nxt)del(e[i].to);
	return;
}
void dfs(int k)
{
	for(int i = SAM::lin[k];i != 0;i = SAM::e[i].nxt)
	{
		if(SAM::e[i].to == son[k])continue; 
		dfs(SAM::e[i].to);
		del(SAM::e[i].to);
	}
	if(son[k] != 0)dfs(son[k]);
	if(SAM::s[k].rig)QUERY::insert(SAM::s[k].rig);
	for(int i = SAM::lin[k];i != 0;i = SAM::e[i].nxt)
	{
		if(SAM::e[i].to != son[k])add(SAM::e[i].to);
	}
	QUERY::query(k);
	return;
}
int main()
{
	scanf("%s%s",S + 1,T + 1);
	l1 = strlen(S + 1),l2 = strlen(T + 1);
	for(int i = l1 + 1;i < l1 * 2;++i)S[i] = S[i - l1];
	for(int i = 1;i < l1 * 2;++i)SAM::extend(S[i] - 'a',i);
	SAM::last = 1;
	for(int i = 1;i <= l2;++i)
	{
		SAM::extend(T[i] - 'a',0);
		SAM::pos[i] = SAM::last;
	}
	SAM::build();
	SAM::dfs(SAM::root);
	scanf("%d",&q);
	int l,r,k;
	for(int i = 1;i <= q;++i)
	{
		l = rd();r = rd();k = rd();
		int pos = SAM::getpos(l,r);
		QUERY::p[i].len = r - l + 1;QUERY::p[i].k = k;
		QUERY::v[pos].push_back(i);
	}
	dfs1(1,1);
	QUERY::s.insert(2 * l1);
	dfs(1);
	for(int i = 1;i <= q;++i)printf("%d\n",QUERY::p[i].ans);
	return 0;
}
        Copyright © 2020
        
          wjh15101051
        
      
      ღゝ◡╹)ノ♡
     Date: Wed Mar 13 19:25:51 CST 2019
          Date: Wed Mar 13 19:25:51 CST 2019
           In Category:
          In Category:
           In tag:
          In tag:
 
         Timeline
            Timeline
           About
            About
           Toolbox
            Toolbox
           Friends
              Friends