牛客练习赛64 F.如果我让你查回文你还爱我吗

链接

点击跳转

题解

挺神的一个题,这个题就是要求这样一个东西:对于一个区间中的每一个回文中心,看一下这个回文中心最多能往两边延伸几格,使得回文串不能延伸到查询区间外面去。然后这个最多延伸的格数就是其对答案的贡献。

会发现,位于左半个区间的回文中心,在延伸的过程中只可能被区间的左边界截断,位于右半个区间的,只可能被区间的右边界截断。

因此我们分开处理

以左半段为例,问题转化成求 i = l ( l + r ) / 2 m i n ( r [ i ] , i l + 1 ) \sum _{i=l}^{(l+r)/2}min(r[i],i-l+1) ,这个东西直观看上去很不好处理,这个时候就要用到出题人给的神奇做法:

对于每个 i i ,我给区间 [ i r [ i ] + 1 , i ] [i-r[i]+1,i] 这些位置加一,然后我要求的东西就转化成了区间 [ l , + ) [l,+\infin) 的和

太神了,想不到想不到

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 400010
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
    ll c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
struct Manacher
{
    int r[maxn], p[maxn], n;
    void clear(){cl(r), cl(p);}
    void calc(char *s, int N)
    {
        n=N;
        int i, j, mx(0), center;
        r[0]=-2;
        for(i=1;i<=N;i++)r[2*i]=s[i];
        for(i=1;i<=N;i++)r[2*i-1]=-1;
        r[2*N+1]=-1;
        for(i=1;i<=2*N+1;i++)
        {
            if(mx>=i)p[i]=min(p[2*center-i],mx-i+1);
            else p[i]=1;
            while(r[i-p[i]]==r[i+p[i]])p[i]++;
            if(i+p[i]-1>mx)
            {
                mx=i+p[i]-1;
                center=i;
            }
        }
    }
}mnc;
char s[maxn];
ll n, id[maxn], l[maxn], r[maxn], ans[maxn], q;
struct SegmentTree
{
    ll mn[maxn<<2], mx[maxn<<2], sum[maxn<<2], add[maxn<<2], set[maxn<<2], L[maxn<<2], R[maxn<<2];
    void maketag_set(ll o, ll v)
    {
        add[o]=0;
        set[o]=v;
        mx[o]=mn[o]=v;
        sum[o]=(R[o]-L[o]+1)*v;
    }
    void maketag_add(ll o, ll v)
    {
        add[o]+=v;
        mx[o]+=v, mn[o]+=v;
        sum[o]+=(R[o]-L[o]+1)*v;
    }
    void pushdown(ll o)
    {
        if(L[o]==R[o])return;
        if(~set[o])
        {
            maketag_set(o<<1,set[o]);
            maketag_set(o<<1|1,set[o]);
            set[o]=-1;
        }
        if(add[o])
        {
            maketag_add(o<<1,add[o]);
            maketag_add(o<<1|1,add[o]);
            add[o]=0;
        }
    }
    void pushup(ll o)
    {
        mx[o]=max(mx[o<<1],mx[o<<1|1]);
        mn[o]=min(mn[o<<1],mn[o<<1|1]);
        sum[o]=sum[o<<1]+sum[o<<1|1];
    }
    void build(ll o, ll l, ll r, ll* array=NULL)
    {
        ll mid(l+r>>1);
        L[o]=l, R[o]=r;
        add[o]=0;
        set[o]=-1;
        if(l==r)
        {
            if(array)mn[o]=mx[o]=sum[o]=array[l];
            else mn[o]=mx[o]=sum[o]=0;
            return;
        }
        build(o<<1,l,mid,array);
        build(o<<1|1,mid+1,r,array);
        pushup(o);
    }
    void Set(ll o, ll l, ll r, ll v)
    {
        ll mid(L[o]+R[o]>>1);
        if(l<=L[o] and r>=R[o]){maketag_set(o,v);return;}
        pushdown(o);
        if(l<=mid)Set(o<<1,l,r,v);
        if(r>mid)Set(o<<1|1,l,r,v);
        pushup(o);
    }
    void Add(ll o, ll l, ll r, ll v)
    {
        ll mid(L[o]+R[o]>>1);
        if(l<=L[o] and r>=R[o]){maketag_add(o,v);return;}
        pushdown(o);
        if(l<=mid)Add(o<<1,l,r,v);
        if(r>mid)Add(o<<1|1,l,r,v);
        pushup(o);
    }
    ll Sum(ll o, ll l, ll r)
    {
        pushdown(o);
        ll mid(L[o]+R[o]>>1), ans(0);
        if(l<=L[o] and r>=R[o])return sum[o];
        if(l<=mid)ans+=Sum(o<<1,l,r);
        if(r>mid)ans+=Sum(o<<1|1,l,r);
        return ans;
    }
    ll Min(ll o, ll l, ll r)
    {
        ll mid(L[o]+R[o]>>1), ans(linf);
        if(l<=L[o] and r>=R[o])return mn[o];
        pushdown(o);
        if(l<=mid)ans=min(ans,Min(o<<1,l,r));
        if(r>mid)ans=min(ans,Min(o<<1|1,l,r));
        return ans;
    }
    ll Max(ll o, ll l, ll r)
    {
        ll mid(L[o]+R[o]>>1), ans(-linf);
        if(l<=L[o] and r>=R[o])return mx[o];
        pushdown(o);
        if(l<=mid)ans=max(ans,Max(o<<1,l,r));
        if(r>mid)ans=max(ans,Max(o<<1|1,l,r));
        return ans;
    }
}segtree;
int main()
{
    ll i, j;
    n=read(), q=read();
    scanf("%s",s+1);
    mnc.calc(s,n);
    // rep(i,1,2*n)printf("p[%d]=%d\n",i,mnc.p[i]);
    rep(i,1,q)l[i]=2*read()-1, r[i]=2*read()+1, id[i]=i;

    sort(id+1,id+q+1,[&](ll a, ll b){return l[a]+r[a] < l[b]+r[b]; });

    segtree.build(1,1,2*n+1);
    j=1;
    rep(i,1,q)
    {
        while(j<=(l[id[i]]+r[id[i]]>>1))
        {
            segtree.Add(1,j-mnc.p[j]+1,j,1);
            j++;
        }
        ans[id[i]] += segtree.Sum(1,l[id[i]],2*n);
    }

    segtree.build(1,1,2*n+1);
    j=2*n+1;
    drep(i,q,1)
    {
        while(j>(l[id[i]]+r[id[i]]>>1))
        {
            segtree.Add(1,j,j+mnc.p[j]-1,1);
            j--;
        }
        ans[id[i]] += segtree.Sum(1,1,r[id[i]]);
    }

    rep(i,1,q)
    {
        ans[i] -= (r[i]+1>>1) - (l[i]>>1);
        printf("%lld\n",ans[i]/2);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/106298263