Subpalindromes URAL - 1989 (字符串hash+线段树)
作者:互联网
题意:给定一个小写字母组成的字符串,m次操作,每次修改单个位置的字符或者查询[l,r]这段子串是否是回文串,给出Yes/No
思路:输入字符串s0,设字符串的逆序串为s1。
如果这题没有单点修改的话,直接对s0 s1求出hash数组,然后对于[l,r]判断左边区间的hash值是否等于右半区间的hash值 。
但是涉及单点修改的话,就需要线段树维护区间hash值。
而且需要两棵线段树对s0 s1分别维护。
hash的区间合并:
另外还有一些细节,比如查询时的写法(返回结构体)
见代码注释
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int maxn = 1e5+7;
const ll inf = 34359738370;
const int has = 99959;
//给定字符串 m次操作 修改单个字符 或者查询[l,r]子串是否是回文串
//思路:开2个线段树分别维护左到右的区间hash值 右到左的区间hash值 每次单点修改
ull p[maxn];//p p^2 p^3...
int n,m;
char s[2][maxn];
struct segt
{
int l,r;
ull v;
segt operator + (const segt &a)const //重载+ 变成区间合并
{
segt res;
res.l=l,res.r=a.r;
res.v=v*p[(a.r-a.l+1)]+a.v;
return res;
}
}tree[2][maxn<<2];
inline int lc(int &rt){ return rt<<1 ; }
inline int rc(int &rt){ return rt<<1|1 ; }
inline void pushup(int &rt,int k){ tree[k][rt] = tree[k][lc(rt)] + tree[k][rc(rt)] ; }
inline void build(int rt,int l,int r,int k)
{
tree[k][rt].l=r,tree[k][rt].r=r;
if(l == r)
{
tree[k][rt].v=s[k][l]-'a'+1;
return ;
}
int mid=(l+r)>>1;
build(lc(rt),l,mid,k);
build(rc(rt),mid+1,r,k);
pushup(rt,k);
}
inline void updata(int rt,int x,ull v,int k)
{
if(tree[k][rt].l == tree[k][rt].r)
{
tree[k][rt].v=v;
return ;
}
int mid=(tree[k][rt].l + tree[k][rt].r)>>1;
if(x<=mid) updata(lc(rt),x,v,k);
else updata(rc(rt),x,v,k);
pushup(rt,k);
}
inline segt query(int rt,int l,int r,int vl,int vr,int k)
{
//这里用带4个return的这种写法比较简单 因为涉及区间的特殊合并
if(vl<=l && r<=vr) return tree[k][rt];
int mid=(l+r)>>1;
if(vl>mid) return query(rc(rt),mid+1,r,vl,vr,k);
else if(vr<=mid) return query(lc(rt),l,mid,vl,vr,k);
return query(lc(rt),l,mid,vl,vr,k)+query(rc(rt),mid+1,r,vl,vr,k);
}
int main()
{
p[1]=has;
for(int i=2;i<=maxn;i++) p[i]=p[i-1]*has;
while(~scanf("%s",s[0]+1)){
n=strlen(s[0]+1);
for(int i=1;i<=n;i++) s[1][i]=s[0][n-i+1];
scanf("%d",&m);
char q[100],ch[2];
int a,b;
build(1,1,n,0);
build(1,1,n,1);
while(m--)
{
scanf("%s",q);
if(q[0]=='c')
{
scanf("%d %s",&a,ch);
ull v=ch[0]-'a'+1;
updata(1,a,v,0);
updata(1,n-a+1,v,1);
}
else if(q[0]=='p')
{
scanf("%d %d",&a,&b);
if(a==b)
{
puts("Yes");
continue;
}
int mid=(a+b)>>1;
int r=mid;
if((b-a)%2==0) r=mid-1;//奇数长度 左边区间舍弃中间那个字符
ull t1=query(1,1,n,a,r,0).v,t2=query(1,1,n,n-b+1,n-mid,1).v;
if(t1 == t2)puts("Yes");
else puts("No");
}
}
}
return 0;
}
标签:rt,hash,int,tree,mid,1989,return,URAL 来源: https://blog.csdn.net/qq_46030630/article/details/114307477