给定长度为
的
字符串
(下标范围为
),执行两个操作:
,
取最大
时,
,但实际数据可能会更大,超时时必然的
-
区间取反:将
这个区间中的全部元素进行取反操作,
-
区间数一:输出下标在
这个区间中的所有元素值为
的元素的个数,即
前面有一道简单的题目是相同的区间取操作+单点查询
的值为
还是
,解决的办法是维护区间的取反次数
,如果
为奇数,那么输出
,否则输出
但是这里区间查询
这个区间中的
的的个数,但是是一模一样的,没有任何区别!
结果就是我以为线段树不能解决,然后想到用分块来做:
分块+二分优化:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 5e5 + 10;
int n, q, block_size;
vector<int> block[N];
int a[N], cnt[N];
void reset_block(int idx){
block[idx].clear();
int l = (idx - 1) * block_size + 1;
int r = min(idx * block_size, n);
for(int i = l; i <= r; i ++) block[idx].push_back(a[i]);
sort(block[idx].begin(), block[idx].end());
}
void block_cnt(int l, int r){
int idx_l = (l - 1) / block_size + 1;
int idx_r = (r - 1) / block_size + 1;
if(idx_l == idx_r){
for(int i = l; i <= r; i ++) a[i] = 1 - a[i];
reset_block(idx_l);
}
else{
int left_end = idx_l * block_size;
for(int i = l; i <= left_end; i ++) a[i] = 1 - a[i];
reset_block(idx_l);
for(int i = idx_l + 1; i <= idx_r - 1; i ++) cnt[i] += 1;
int right_begin = (idx_r - 1) * block_size + 1;
for(int i = right_begin; i <= r; i ++) a[i] = 1 - a[i];
reset_block(idx_r);
}
}
int query(int l, int r){
int res = 0;
int idx_l = (l - 1) / block_size + 1;
int idx_r = (r - 1) / block_size + 1;
if(idx_l == idx_r){
for(int i = l; i <= r; i ++){
if(a[i] == 1 && !(cnt[idx_l] & 1)) res ++;
else if(a[i] == 0 && cnt[idx_l] & 1) res ++;
}
}
else{
int left_end = idx_l * block_size;
for(int i = l; i <= left_end; i ++){
if(a[i] == 0 && cnt[idx_l] & 1) res ++;
else if(a[i] == 1 && !(cnt[idx_l] & 1)) res ++;
}
for(int i = idx_l + 1; i <= idx_r - 1; i ++){
auto it = lower_bound(block[i].begin(), block[i].end(), 1);
if(it == block[i].begin()){
if(!(cnt[i] & 1)) res += block_size;
}
else if(it == block[i].end()){
if(cnt[i] & 1) res += block_size;
}
else{
// it --;
int pos = it - block[i].begin();
if(cnt[i] & 1) res += pos;
else res += block_size - pos;
}
}
int right_begin = (idx_r - 1) * block_size + 1;
for(int i = right_begin; i <= r; i ++){
if(a[i] == 0 && cnt[idx_r] & 1) res ++;
else if(a[i] == 1 && !(cnt[idx_r] & 1)) res ++;
}
}
return res;
}
signed main(){
HelloWorld;
cin >> n >> q;
for(int i = 1; i <= n; i ++){
char sh; cin >> sh;
a[i] = sh - '0';
}
block_size = (int)sqrt(n) + 1;
int total_block = (n - 1) / block_size + 1;
for(int i = 1; i <= total_block; i ++) reset_block(i);
while(q --){
int op; cin >> op;
if(op == 1){
int l, r; cin >> l >> r;
block_cnt(l, r);
}
else{
int l, r; cin >> l >> r;
cout << query(l, r) << endl;
}
}
return 0;
}
结果超时了,时间复杂度一般为
如果
取最大
时,则
,则不会超时
正确的线段树做法:
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 5e5 + 10;
struct Node{
int l, r;
int sum, cnt;
}tr[4 * N];
int n, q, a[N];
void push_up(int u){
tr[u].sum = (tr[u << 1].sum + tr[u << 1 | 1].sum);
}
void push_down(int u){
if(tr[u].cnt & 1){
tr[u << 1].cnt += 1;
tr[u << 1].sum = (tr[u << 1].r - tr[u << 1].l + 1) - tr[u << 1].sum;
tr[u << 1 | 1].cnt += 1;
tr[u << 1 | 1].sum = (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) - tr[u << 1 | 1].sum;
tr[u].cnt += 1;
}
}
void build(int u, int l, int r){
if(l == r) tr[u] = {l, r, a[l], 0};
else{
tr[u] = {l, r, 0, 0};
int mid = (tr[u].l + tr[u].r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
push_up(u);
}
}
void modify(int u, int l, int r){
if(l <= tr[u].l && tr[u].r <= r){
tr[u].sum = (tr[u].r - tr[u].l + 1) - tr[u].sum;
tr[u].cnt += 1;
return ;
}
else{
push_down(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) modify(u << 1, l, r);
if(r > mid) modify(u << 1 | 1, l, r);
push_up(u);
}
}
int query(int u, int l, int r){
if(l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
else{
int res = 0;
push_down(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) res += query(u << 1, l, r);
if(r > mid) res += query(u << 1 | 1, l, r);
return res;
}
}
signed main(){
HelloWorld;
cin >> n >> q;
for(int i = 1; i <= n; i ++){
char sh; cin >> sh;
a[i] = sh - '0';
}
build(1, 1, n);
while(q --){
int op; cin >> op;
if(op == 1){
int l, r; cin >> l >> r;
modify(1, l, r);
}
else{
int l, r; cin >> l >> r;
cout << query(1, l, r) << endl;
}
}
return 0;
}



京公网安备 11010502036488号