【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);
}

猜你喜欢

转载自www.cnblogs.com/sadstone/p/9220039.html
今日推荐