题目来源
https://codeforces.ml/problemset/problem/1477/B
题意分析
给定两个长度为n的01序列,分别表示a,b。再给定一个q,表示有q个询问区间。在保证每次询问中,区间内所有数字相同的情况下, 可以修改严格小于区间长度一半的数。问在q次操作之后,能否实现将a序列变成b序列。
思路分析
对于q个询问区间进行逆序操作。根据n和q的数据范围来看,因为q次询问必须遍历,所以最后的时间复杂度可能是O(qlogn)。于是就有了用线段树维护区间和来解决区间01覆盖的问题,一次覆盖就是一个区间修改。最后判断所有操作后的最终序列是否与a序列相同即可。
code
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 7;
int a[maxn], b[maxn];
int tr[maxn << 2], lz[maxn << 2];
int ql[maxn], qr[maxn];
int pre[maxn];
void build(int k, int l, int r){
if (l == r){
lz[k] = -1; tr[k] = b[l]; return;
}
int mid = l + r >> 1;
build(k<<1, l, mid);
build(k<<1|1, mid+1, r);
tr[k] = tr[k<<1] + tr[k<<1|1];
lz[k] = -1;
}
void pushdown(int k, int l, int r, int mid){
if (lz[k] == -1) return;
if (lz[k]){
lz[k<<1] = 1;
lz[k<<1|1] = 1;
tr[k<<1] = mid - l + 1;
tr[k<<1|1] = r - mid;
}else{
lz[k<<1] = 0;
lz[k<<1|1] = 0;
tr[k<<1] = 0;
tr[k<<1|1] = 0;
}
lz[k] = -1;
}
void update(int k, int l, int r, int L, int R, int x){
if (L <= l && r <= R){
lz[k] = x; tr[k] = x * (r - l + 1); return;
}
int mid = l + r >> 1;
pushdown(k, l, r, mid);
if (L <= mid) update(k<<1, l, mid, L, R, x);
if (mid < R) update(k<<1|1, mid+1, r, L, R, x);
tr[k] = tr[k << 1] + tr[k << 1 | 1];
}
int sum(int k, int l, int r, int L, int R){
if (L <= l && r <= R) return tr[k];
int mid = l + r >> 1;
pushdown(k, l, r, mid);
int ans = 0;
if (L <= mid) ans += sum(k<<1, l, mid, L, R);
if (mid < R) ans += sum(k<<1|1, mid+1, r, L, R);
return ans;
}
int main(){
int t; scanf("%d", &t);
while (t --){
int n, q; scanf("%d%d", &n, &q);
for (int i=1; i<=n; i++) scanf("%1d", &a[i]);
for (int i=1; i<=n; i++) scanf("%1d", &b[i]);
for (int i=1; i<=n; i++) pre[i] = pre[i-1] + a[i];
build(1, 1, n);
for (int i=1; i<=q; i++) scanf("%d%d", &ql[i], &qr[i]);
bool flag = false;
for (int i=q; i>=1; i--){
int l = ql[i], r = qr[i];
int one = sum(1, 1, n, l, r), zero = r - l + 1 - one;
// cout << "l: " << l << " r:" << r << " one: " << one << " " << zero << endl;
if (one == zero){
// cout << "nei" << endl;
flag = true; break;
}
if (one > zero) update(1, 1, n, l, r, 1);
else update(1, 1, n, l, r, 0);
}
if (flag){
printf("NO\n"); continue;
}
for (int i=1; i<=n; i++){
int one = sum(1, 1, n, 1, i);
if (one != pre[i]){
// cout << "i: " << i << " one: " << one << endl;
flag = true; break;
}
}
if (flag) printf("NO\n");
else printf("YES\n");
}
return 0;
}