• 牛客练习赛64 如果我让你查回文你还爱我吗 线段树 树状数组 manacher 计数 区间本质不同回文串个数


    LINK:如果我让你查回文你还爱我吗

    了解到了这个模板题. 果然我不会写2333...

    考试的时候想到了一个非常辣鸡的 线段树合并+莫队的做法 过不了不再赘述.

    当然也想到了manacher不过不太会用 所以就自闭了。

    这道题 容易考虑到manacher而不是PAM.

    考虑 在扩充后的字符串上做这个问题 这样就不需要考虑偶数回文串的条件了.

    离线之后右端点不断移动 容易发现一个问题 某个点为中心的回文串个数标记在左端点上不过此时可能左端点够而右端点不太行。

    一个trick 将区间分成两半 这样就没有这个影响了.

    然后查询直接查就行了 可以线段树维护区间加当然也可以树状数组维护.

    值得一提的是 可以发现每次赋值 某一段整体赋值很好做 在奇数回文串的时候这样做容易发现是两倍。

    偶数则不然 这里减掉区间中所有的单独的#就可以发现 答案刚好是二倍了.

    const int MAXN=200010<<1;
    int n,Q;
    struct jl{int l,r;int id;}sl[MAXN],sr[MAXN];
    inline int cmpl(jl a,jl b){return a.r<b.r;}
    inline int cmpr(jl a,jl b){return a.l>b.l;}
    struct wy
    {
    	int l,r;
    	ll sum,tag;
    }t[MAXN<<2];
    char a[MAXN],b[MAXN];
    int p[MAXN];ll ans[MAXN];
    inline void Manacher()
    {
    	b[0]='#';b[1]='$';
    	rep(1,n,i)b[i<<1]=a[i],b[i<<1|1]='$';
    	n=n<<1|1;b[n+1]='0';
    	int mx=0,mid=0;
    	rep(1,n,i)
    	{
    		if(mx>i)p[i]=min(p[(mid<<1)-i],mx-i);
    		else p[i]=1;
    		while(b[i-p[i]]==b[i+p[i]])++p[i];
    		if(p[i]+i>mx)mx=p[i]+i,mid=i;
    	}
    }
    inline void pushdown(int p)
    {
    	int mid=(l(p)+r(p))>>1;
    	sum(zz)+=(ll)tag(p)*(mid-l(p)+1);
    	sum(yy)+=(ll)tag(p)*(r(p)-mid);
    	tag(zz)+=tag(p);tag(yy)+=tag(p);
    	tag(p)=0;return;
    }
    inline void change(int p,int l,int r,int x)
    {
    	if(l<=l(p)&&r>=r(p))
    	{
    		sum(p)+=(ll)(r(p)-l(p)+1)*x;
    		tag(p)+=x;return;
    	}
    	int mid=(l(p)+r(p))>>1;
    	if(tag(p))pushdown(p);
    	if(l<=mid)change(zz,l,r,x);
    	if(r>mid)change(yy,l,r,x);
    	sum(p)=sum(zz)+sum(yy);
    }
    inline ll ask(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))return sum(p);
    	int mid=(l(p)+r(p))>>1;ll cnt=0;
    	if(tag(p))pushdown(p);
    	if(l<=mid)cnt+=ask(zz,l,r);
    	if(r>mid)cnt+=ask(yy,l,r);
    	return cnt;
    }
    inline void build(int p,int l,int r)
    {
    	l(p)=l;r(p)=r;
    	sum(p)=tag(p)=0;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	build(zz,l,mid);
    	build(yy,mid+1,r);
    }
    inline void solve_l()
    {
    	build(1,1,n);int flag=1;
    	sort(sl+1,sl+1+Q,cmpl);
    	rep(1,n,i)
    	{
    		change(1,i-p[i]+1,i,1);
    		while(sl[flag].r<=i&&flag<=Q)
    		{
    			ans[sl[flag].id]+=ask(1,sl[flag].l,sl[flag].r);
    			++flag;
    		}
    	}
    }
    inline void solve_r()
    {
    	build(1,1,n);int flag=1;
    	sort(sr+1,sr+1+Q,cmpr);
    	fep(n,1,i)
    	{
    		change(1,i,i+p[i]-1,1);
    		while(sr[flag].l>=i&&flag<=Q)
    		{
    			ans[sr[flag].id]+=ask(1,sr[flag].l,sr[flag].r);
    			++flag;
    		}
    	}
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	gt(n);gt(Q);gc(a);
    	Manacher();
    	rep(1,Q,i)
    	{
    		int get(l),get(r);
    		ans[i]-=(r-l+2);
    		l=l<<1;--l;r=r<<1;++r;
    		int mid=(l+r)>>1;
    		sl[i]=(jl){l,mid,i};
    		sr[i]=(jl){mid+1,r,i};
    	}
    	solve_l();solve_r();
    	rep(1,Q,i)putl(ans[i]>>1);
    	return 0;
    }
    
  • 相关阅读:
    ASP.NET的运行原理与运行机制
    VS2008快捷键
    (五)SubSonic的存储过程操作
    110个Oracle常用函数整理汇总
    ASP.NET中HttpModule和HttpHandler的作用及用法
    报表统计(sql面试题)
    ASP.NET C# 数字格式化输出
    ASP.NET Global.ascx 事件大全
    ASP.NET中GUID
    asp.net 页面转向 Response.Redirect, Server.Transfer, Server.Execute的区别
  • 原文地址:https://www.cnblogs.com/chdy/p/12951403.html
Copyright © 2020-2023  润新知