======>蒟蒻的博客,写错的地方,请见谅。
题目:传送门
题意:给你三个整数n,m,k, n 代表一个字符串的长度为n。紧接着有 m + k 个操作。将 l 到 r 的字符全部更换为字符 c ,或查询从 l 到 r,该子段字符串循环节是否为 c.
思路:
由于该蒟蒻很少写哈希,而且又很菜,花了挺长时间写这个题目的,也算是有挺大的收获,对多项式哈希理解很多。
多项式哈希,即:
(1 < i <= n,Hash[0] = 0)
我们将Hash[i - 1] 也这样展开, 就得到 ························· ①
所以很容易得到公式
······························ ②
对于线段树维护哈希值,建树时pushup()的操作,我们可以这样理解:
Hash[r] 其实也就是 Hash(1,r),Hash[l - 1] 也就是 Hash(1,l - 1)。
那么设 mid = (1 + r) >> 1,
那么按线段树的操作, (1,r) 也就被分为区间 (1,mid) , (mid + 1,r),根据公式②,此时的 mid 可以= l - 1,移项 就有
Hash(1,r) = Hash(1,mid) * pow_p[右子树的长度] + Hash(mid + 1,r)
也就是pushup()时, sum[i] = sum[i << 1] * pow_p[r - mid] + sum[i << 1 | 1] .
区间更新 update() 的时候为什么用的是 pow_p 的前缀和:
请仔细看等式①,当 l 到 r 区间的字符全部变为 c 时,字符 c 可以提出来,提出来之后,剩下的也就是一个前缀和
线段树维护哈希值,查询的时候也值得注意,因为左子树是需要乘上一个 pow[x] 的 /// x未知.
这个题剩下的就是循环节的问题,如果 c == r - l + 1,那么肯定是YES,如果 != , 直接判断 Hash(l,r - c) == Hash(l + c,r) ? 即可。
AC代码:
#include
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define INT(t) int t; scanf("%d",&t)
#define LLI(t) LL t; scanf("%I64d",&t)
#define pll pair
#define ls (i << 1)
#define rs (i << 1) | 1
using namespace std;
const int maxn = 1e5 + 10;
int n,m,k;
const LL p = 13331;
const LL mod = 1e9 + 7;
LL pow1[maxn];
LL pow1_sum[maxn];
struct xx{
LL hash1;
int flag;
}T[maxn * 4];
void pushup(int l,int r,int i){
int mid = (l + r) >> 1;
T[i].hash1 = ((T[ls].hash1 * pow1[r - mid]) % mod + T[rs].hash1) % mod;
}
void pushdown(int l,int r,int i){
if(T[i].flag == -1) return ;
int mid = (l + r) >> 1;
T[ls].hash1 = (T[i].flag * pow1_sum[mid - l]) % mod;
T[rs].hash1 = (T[i].flag * pow1_sum[r - mid - 1]) % mod;
T[ls].flag = T[rs].flag = T[i].flag;
T[i].flag = -1;
}
void build(int l,int r,int i){
T[i].flag = -1;
if(l == r){
char ch; scanf(" %c",&ch);
T[i].hash1 = ch - '0';
return ;
}
int mid = (l + r) >> 1;
build(l,mid,ls);
build(mid + 1,r,rs);
pushup(l,r,i);
}
void update(int l,int r,int ql,int qr,int i,int ch){
if(ql <= l && r <= qr){
T[i].hash1 = (ch * pow1_sum[r - l]) % mod;
T[i].flag = ch;
return ;
}
pushdown(l,r,i);
int mid = (l + r) >> 1;
if(ql <= mid) update(l,mid,ql,qr,ls,ch);
if(qr > mid) update(mid + 1,r,ql,qr,rs,ch);
pushup(l,r,i);
}
LL query(int l,int r,int ql,int qr,int i){
// if(ql <= l && r <= qr)
// return T[i].hash1;
// pushdown(l,r,i);
// int mid = (l + r) >> 1;
// LL ans = 0;
// if(ql > mid) return query(mid + 1,r,ql,qr,rs);
// else if(qr <= mid) return query(l,mid,ql,qr,ls);
// else {
// LL t1 = query(l,mid,ql,qr,ls);
// LL t2 = query(mid + 1,r,ql,qr,rs);
// int tt = min(r,qr) - mid;
// return (t1 * pow1[tt] + t2) % mod;
// }
// pushup(l,r,i);
if(ql <= l && r <= qr) return T[i].hash1;
pushdown(l,r,i);
int mid = (l + r) >> 1;
LL a1 = 0,a2 = 0;
if(ql <= mid) a1 = query(l,mid,ql,qr,ls);
if(qr > mid) a2 = query(mid + 1,r,ql,qr,rs);
return ((a1 * pow1[max(0,min(r,qr) - mid)]) % mod + a2) % mod;
}
int main()
{
pow1[0] = 1;
pow1_sum[0] = 1;
for(int i = 1;i < maxn;++ i){
pow1[i] = (pow1[i - 1] * p) % mod;
pow1_sum[i] = (pow1_sum[i - 1] + pow1[i]) % mod;
}
while(~scanf("%d%d%d",&n,&m,&k)){
build(1,n,1);
for(int i = 1;i <= m + k;++ i){
int op,x,y,z;
scanf("%d%d%d%d",&op,&x,&y,&z);
if(op == 1){
update(1,n,x,y,1,z);
}
else {
if(z == y - x + 1){
printf("YES\n");
continue;
}
LL tx = query(1,n,x,y - z,1);
LL ty = query(1,n,x + z,y,1);
if(tx == ty) printf("YES\n");
else printf("NO\n");
}
}
}
return 0;
}