【JZOJ4645】基因改造计划

Description

给出一个字符串和多组询问,每次询问一个区间内不同位置的回文串个数。

Solution

这里不是询问本质不同的回文串个数,不能用莫队+回文树。

考虑偶回文串较难处理,先在字符中间插入分隔符,变成长度为\(2n+1\)的串,用manacher处理得到以\(i\)为中心长度大于1的回文串个数\(p_i\),考虑原来的询问\([l,r]\),变成了新串上的\([2l-1,2r+1]\),设\(L=2l-1\)\(R=2r+1\),观察一下发现区间答案为:

\[\dfrac{1}{2}(r-l+1+\sum_{i=L}^R min(p_i,i-L,R-i)) \]

\(mid=\dfrac{L+R}{2}\)
\(i>mid\)时(\(i<=mid\)方法类似),需要求\(\sum_{i=mid+1}^Rmin(p_i,R-i)\)的值。
将所有询问离线,考虑一个位置\(i\)的值在\(R\geq i+p_i\)\(p_i\),其余情况则时\(R-i\)(记这种情况为特殊位置)。\(R\)端点右移,遇到询问时统计一下特殊位置的个数与特殊位置上的\(i\)的和就可以计算出局部答案。

至于\(i<=mid\),把字符串倒过来再做一遍即可。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
typedef long long ll;
const int N=3e5+10;
int f[N];
char s[N],a[N];
int tot=0;
void manacher(){
	int lm=0;
	int id,l=tot;
	for(int i=1;i<=l;i++){
		f[i]=lm>i?min(f[2*id-i],lm-i):1;
		while(a[i+f[i]]==a[i-f[i]]) f[i]++;
		if(f[i]+i>lm) lm=f[i]+i,id=i;
	}
	fo(i,1,l) f[i]--;
}
struct node{
	int l,r,mid,p;
}b[N];
int n,m;
ll an[N],cd[N];
bool cmp(node x,node y){
	return x.r<y.r;
}
struct tree{
	ll t,s,sf;
}tr[N<<1];
void update(int v){
	tr[v].t=tr[v<<1].t+tr[(v<<1)+1].t;
	tr[v].s=tr[v<<1].s+tr[(v<<1)+1].s;
	tr[v].sf=tr[v<<1].sf+tr[(v<<1)+1].sf;
}
void build(int v,int l,int r){
	if(l==r){
		tr[v].s=l,tr[v].t=1,tr[v].sf=0;
		return;
	}
	int mid=(l+r)>>1;
	build(v<<1,l,mid),build((v<<1)+1,mid+1,r);
	update(v);
}
void modify(int v,int l,int r,int x){
	if(l==r){
		tr[v].s=tr[v].t=0,tr[v].sf=f[x];
		return;
	}
	int mid=(l+r)>>1;
	x<=mid?modify(v<<1,l,mid,x):modify((v<<1)+1,mid+1,r,x);
	update(v);
}
int now;
ll sum(int v,int l,int r,int x,int y){
	if(l==x && r==y) return tr[v].sf+(ll)now*tr[v].t-tr[v].s;
	int mid=(l+r)>>1;
	if(y<=mid) return sum(v<<1,l,mid,x,y);
	else if(x>mid) return sum((v<<1)+1,mid+1,r,x,y);
	else return sum(v<<1,l,mid,x,mid)+sum((v<<1)+1,mid+1,r,mid+1,y);
}
vector<int> dl[N];
void solve(){
	build(1,1,tot);
	fo(i,1,tot) dl[i+f[i]].push_back(i);
	int p=0;
	fo(i,1,tot){
		now=i;
		int o=dl[i].size();
		fo(j,0,o-1) modify(1,1,tot,dl[i][j]);
		while(p<m && b[p+1].r==i){
			p++;
			an[b[p].p]+=sum(1,1,tot,b[p].mid,b[p].r);
			cd[b[p].p]=(b[p].r-b[p].l)/2;
		}
	}
	fo(i,1,tot) dl[i].clear();
}
int main()
{
	freopen("gene.in","r",stdin);
	freopen("gene.out","w",stdout);
	scanf("%d %d",&n,&m);
	scanf("%s",s+1);
	fo(i,1,n) a[++tot]='#',a[++tot]=s[i];
	a[++tot]='#';
	a[0]='*';
	manacher();
	fo(i,1,m){
		scanf("%d %d",&b[i].l,&b[i].r),b[i].p=i;
		b[i].l=2*b[i].l-1,b[i].r=2*b[i].r+1;
		b[i].mid=(b[i].l+b[i].r)/2;
	}
	sort(b+1,b+m+1,cmp);
	solve();
	reverse(f+1,f+tot+1);
	fo(i,1,m){
		int l=b[i].l,r=b[i].r;
		b[i].l=tot-r+1,b[i].r=tot-l+1;
		b[i].mid=(b[i].l+b[i].r)/2+1;
	}
	sort(b+1,b+m+1,cmp);
	solve();
	fo(i,1,m) printf("%lld\n",(an[i]+cd[i])/2);
}
posted @ 2018-06-24 11:54  sadstone  阅读(170)  评论(0编辑  收藏  举报