[ABC430G] Range Set Modifying Query 题解
Range Set Modifying Query 题解
分块
好玩的数据结构题
看到这道题就有一种分块的欲望。记
先用一个 bitset 维护一下每个集合的状态,有数
对于一个零散块我们直接暴力重构,维护一下每个块的最大值和最大值出现的次数即可,现在我们只需要考虑一个整块如何维护即可。
对于一个整块,我们发现如果这一个块第
那么我们就成功地解决了这一位上全部都一样的情况,那么有不一样的情况怎么办呢?我稍微推了一下发现推不出来了,但是注意到一个整块被整体覆盖时这一位就全部一样了(废话),也就是说一个整块在两次重构中最多会出现上述不好解决的情况
让我们来分析一下时间复杂度吧。
首先暴力重构的时间复杂度是
需要重构多少次呢?每次修改操作整块上的全部一样的位不会变少,只有零散块上一样的位会变少,那么一次操作后总的需要重构的次数最多增加
查询的时间复杂度是
总时间复杂度为
CODE
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <cmath>
using namespace std;
typedef long long LL;
const int MAX_N = 3e5+5, SQRT_N = 707, V = 60, MAX_V = 65;
int n, q;
namespace blocks {
int block_number, block_length, b_l[SQRT_N], b_r[SQRT_N], bb[MAX_N], mx[SQRT_N], num[SQRT_N];
bitset<V> is[SQRT_N], a[MAX_N], tag[SQRT_N][2];
void rebuild (int b) {
is[b].set();
int l = b_l[b], r = b_r[b];
mx[b] = 0;
num[b] = 0;
for(int i = l; i <= r; i ++) {
a[i] &= tag[b][0];
a[i] |= tag[b][1];
if(i > l) {
is[b] &= ~(a[i-1] ^ a[i]);
}
if((int)a[i].count() > mx[b]) {
mx[b] = a[i].count();
num[b] = 1;
}
else if((int)a[i].count() == mx[b]) {
++ num[b];
}
}
tag[b][0].set();
tag[b][1].reset();
}
void init (int n) {
block_length = sqrt(n+0.5);
if(block_length >= 459) block_length = 459;
block_number = (n + block_length - 1) / block_length;
for(int i = 1; i <= block_number; i ++) {
b_l[i] = (i-1)*block_length+1;
if(i == block_number) b_r[i] = n;
else b_r[i] = i*block_length;
for(int j = b_l[i]; j <= b_r[i]; j ++) {
bb[j] = i;
a[j].reset();
}
rebuild(i);
}
}
void add (int l, int r, int x) {
int bl = bb[l], br = bb[r];
if(bl == br) {
rebuild(bl);
for(int i = l; i <= r; i ++) {
a[i][x] = 1;
}
rebuild(bl);
return;
}
rebuild(bl);
for(int i = l; i <= b_r[bl]; i ++) {
a[i][x] = 1;
}
rebuild(bl);
++ bl;
rebuild(br);
for(int i = b_l[br]; i <= r; i ++) {
a[i][x] = 1;
}
rebuild(br);
-- br;
for(int i = bl; i <= br; i ++) {
if(is[i][x] == 1) {
if(tag[i][0][x] == 0) ++ mx[i];
else if(tag[i][1][x] == 0 && a[b_l[i]][x] == 0) ++ mx[i];
tag[i][0][x] = 1;
tag[i][1][x] = 1;
}
else {
tag[i][0][x] = 1;
tag[i][1][x] = 1;
rebuild(i);
}
}
}
void remove (int l, int r, int x) {
int bl = bb[l], br = bb[r];
if(bl == br) {
rebuild(bl);
for(int i = l; i <= r; i ++) {
a[i][x] = 0;
}
rebuild(bl);
return;
}
rebuild(bl);
for(int i = l; i <= b_r[bl]; i ++) {
a[i][x] = 0;
}
rebuild(bl);
++ bl;
rebuild(br);
for(int i = b_l[br]; i <= r; i ++) {
a[i][x] = 0;
}
rebuild(br);
-- br;
for(int i = bl; i <= br; i ++) {
if(is[i][x] == 1) {
if(tag[i][1][x] == 1) -- mx[i];
else if(tag[i][0][x] == 1 && a[b_l[i]][x] == 1) -- mx[i];
tag[i][0][x] = 0;
tag[i][1][x] = 0;
}
else {
tag[i][0][x] = 0;
tag[i][1][x] = 0;
rebuild(i);
}
}
}
pair<int,int> query (int l, int r) {
int bl = bb[l], br = bb[r];
int mxs = 0, nums = 0;
if(bl == br) {
rebuild(bl);
for(int i = l; i <= r; i ++) {
if((int)a[i].count() > mxs) {
mxs = a[i].count();
nums = 1;
}
else if((int)a[i].count() == mxs) {
++ nums;
}
}
return {mxs, nums};
}
rebuild(bl);
for(int i = l; i <= b_r[bl]; i ++) {
if((int)a[i].count() > mxs) {
mxs = a[i].count();
nums = 1;
}
else if((int)a[i].count() == mxs) {
++ nums;
}
}
++ bl;
rebuild(br);
for(int i = b_l[br]; i <= r; i ++) {
if((int)a[i].count() > mxs) {
mxs = a[i].count();
nums = 1;
}
else if((int)a[i].count() == mxs) {
++ nums;
}
}
-- br;
for(int i = bl; i <= br; i ++) {
if(mx[i] > mxs) {
mxs = mx[i];
nums = num[i];
}
else if(mx[i] == mxs) {
nums += num[i];
}
}
return {mxs, nums};
}
}
int main () {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> q;
blocks::init(n);
while(q --) {
int opt, l, r, x;
cin >> opt >> l >> r;
if(opt == 1) {
cin >> x;
blocks::add(l, r, x-1);
}
else if(opt == 2) {
cin >> x;
blocks::remove(l, r, x-1);
}
else {
pair<int, int> k = blocks::query(l, r);
cout << k.first << " " << k.second << "\n";
}
}
return 0;
}