周期串查询(哈希加线段树 或灵性做法)
题目大意
- 有一个串只包含数字字符。串的长度为n,下标从1开始。
- 有两种操作方式:
- 1 l r c (1≤l≤r≤n, c是数字字符),表示将l到r这一段的字符全部改成c字符;
- 2 l r d (1≤l≤r≤n, 1≤d≤r-l+1),表示询问l到r这一段区间内的子串是否是以d为周期的串。
- 字符串s是以x (1≤x≤|s|),为周期的串的条件是:对于所有的 i从1到|s|-x, si = si + x 都成立。
输入格式
单组测试数据。
第一行有两个整数n, m ,k (1≤n≤10^5, 1≤m+k≤10^5),表示字符串长度和修改次数和询问次数。
第二行给出原始的串包含n位数字字符。
接下来m+k行,每行一个操作。
有两种形式:
1 l r с (1≤l≤r≤n, c是数字字符);
2 l r d (1≤l≤r≤n, 1≤d≤r-l+1)。
输出格式
对于每一个询问,如果该段子串是以d为周期的,输出YES,否则输出NO。
样例
样例输入
3 1 2
112
2 2 3 1
1 1 3 8
2 1 2 1
样例输出
NO
YES
算法分析
- 线段树区间修改 区间查询 线段树的节点存子节点中最大值
- 其实这个线段树主要是优化的作用 如果要求的这个区间中 最大值与最小值相等 那么肯定就是一样的 最后以d为周期查找一下就好
- 关于瞎搞的话………… memset 与 memcpy
Code
Code1
// 比下面那种算法慢 但是很锻炼码力(自闭症患者慎入)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
char s[maxn];
int v[maxn];
int cnt;
int cur[maxn];
struct node{
int rt,l,r,Max,Min,lazy;
}a[maxn << 2];
void build(int rt,int l,int r){
a[rt].l = l;a[rt].r = r;
if(a[rt].l == a[rt].r){a[rt].Max = a[rt].Min = v[l];return;}
int mid = l + r >> 1;
build(rt << 1,l,mid);
build(rt << 1 | 1,mid + 1,r);
a[rt].Max = max(a[rt << 1].Max,a[rt << 1 | 1].Max);
a[rt].Min = min(a[rt << 1].Min,a[rt << 1 | 1].Min);
}
void updata(int rt,int k){
a[rt].Max = a[rt].Min = k;
a[rt].lazy = k;
}
void pushdown(int rt){
updata(rt << 1,a[rt].lazy);
updata(rt << 1 | 1,a[rt].lazy);
a[rt].lazy = 0;
}
void change(int rt,int l,int r,int k){
if(a[rt].l >= l && a[rt].r <= r){
a[rt].Max = a[rt].Min = k;
a[rt].lazy = k;
return;
}
if(a[rt].lazy)pushdown(rt);
int mid = a[rt].l + a[rt].r >> 1;
if(l <= mid)change(rt << 1,l,r,k);
if(r > mid)change(rt << 1 | 1,l,r,k);
a[rt].Max = max(a[rt << 1].Max,a[rt << 1 | 1].Max);
a[rt].Min = min(a[rt << 1].Min,a[rt << 1 | 1].Min);
}
int askmax(int rt,int l,int r){
if(a[rt].l >= l && a[rt].r <= r){
if(a[rt].lazy)pushdown(rt);
return a[rt].Max;
}
if(a[rt].lazy)pushdown(rt);
int mid = a[rt].l + a[rt].r >> 1;
if(r <= mid)return askmax(rt << 1,l,r);
if(l > mid)return askmax(rt << 1 | 1,l,r);
return max(askmax(rt << 1,l,r),askmax(rt << 1 | 1,l,r));
}
int askmin(int rt,int l,int r){
if(a[rt].l >= l && a[rt].r <= r){
if(a[rt].lazy)pushdown(rt);
return a[rt].Min;
}
if(a[rt].lazy)pushdown(rt);
int mid = a[rt].l + a[rt].r >> 1;
if(r <= mid)return askmin(rt << 1,l,r);
if(l > mid)return askmin(rt << 1 | 1,l,r);
return min(askmin(rt << 1,l,r),askmin(rt << 1 | 1,l,r));
}
void first(int rt,int l,int r,int k){
if(a[rt].lazy)pushdown(rt);
if(a[rt].l == a[rt].r){cur[++cnt] = a[rt].Max;return;}
int mid = a[rt].l + a[rt].r >> 1;
if(l <= mid)first(rt << 1,l,r,k);
if(r > mid)first(rt << 1 | 1,l,r,k);
}
bool check(int k){
if(k > cnt)return 0;
for(int i = 1;i <= cnt - k;++i)if(cur[i] != cur[i + k])return 0;
return 1;
}
int main(){
//freopen("Data.in","r",stdin);
//freopen("c.out","w",stdout);
int n,m,K;scanf("%d%d%d",&n,&m,&K);
scanf("%s",s+1);
for(int i = 1;i <= n;++i)v[i] = s[i] - '0';
build(1,1,n);
for(int i = 1;i <= m + K;++i){
int flag,l,r,k;scanf("%d%d%d%d",&flag,&l,&r,&k);
if(flag == 1)change(1,l,r,k);
if(flag == 2){
cnt = 0;
first(1,l,r,k);
if(askmax(1,l,r) == askmin(1,l,r)){
printf("YES
");
continue;
}
if(check(k))printf("YES
");
else printf("NO
");
}
}
return 0;
}
Code2
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
char s[maxn];
int a[maxn],h[maxn];
int main(){
int n,m,k;scanf("%d%d%d",&n,&m,&k);
scanf("%s",s+1);
k += m;
while(k--){
int flag,l,r,k;scanf("%d%d%d%d",&flag,&l,&r,&k);
if(flag == 1)memset(s + l,k + '0',r - l + 1);
if(flag == 2 && memcmp(s + l,s + l + k,r - l - k + 1))printf("NO
");
else if(flag == 2)printf("YES
");
}
return 0;
}