题目大意:
给出一个 n ∗ m n*m n∗m的矩阵,需要对其进行下列操作:
- 1 x y ,将a[x][y] 置 1
- 2 x y ,将a[x][y] 置 0
- 3 x , 将第x行翻转
- 4 x ,回溯到第x个版本
初始全部是0,输出每次操作后矩阵中1的数量
题目思路:
首先具有回溯操作,所以考虑一下主席树
初始思路错了,所以就不再提了。
看把题目复制到百度看到 b i t s e t bitset bitset关键字时,瞬间就懂了.
对于每一次操作,生成一颗线段树维护所有的行。但是行内的怎么维护呢?
行内比较麻烦,完全可以在套一个主席树,但是没有必要!因为可以用 b i t s e t bitset bitset优化掉。每个叶子节点维护一个bitset代表行内的情况,那么就比较好维护了。对于每次操作就都相当于对一个叶子节点进行了操作。
可能会注意到空间复杂度的问题:
b i t s e t bitset bitset按位算,空间相当于 1000 / 32 1000/32 1000/32
对于 1 e 5 1e5 1e5次操作,那么肯定有 100000 ∗ l o g ( 1000 ) ∗ 1000 / 32 = 1000000 ∗ 10 = 10000000 100000 * log(1000) * 1000/32 = 1000000*10 = 10000000 100000∗log(1000)∗1000/32=1000000∗10=10000000
这是完全可以的
所以时间复杂度也同样为: O ( q ∗ l o g ( 1000 ) ∗ 1000 / 32 ) O(q*log(1000)*1000/32) O(q∗log(1000)∗1000/32)
Code:
/*** keep hungry and calm CoolGuang! ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17+7;
const ll maxn = 2e6+700;
const ll mod= 1e9+7;
const ll up = 1e13;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
char c=getchar();T x=0,f=1;while(!isdigit(c)){
if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
struct node{
int l,r,w;
bitset<1005>s;
}t[100000*21];
int root[maxn*21];
int cnt = 0;
void Insert(int &now,int pre,int l,int r,int x,int y,int op){
t[now = ++cnt] = t[pre];
int mid = (l+r)/2;
if(l == r){
if(op == 1) t[now].s.set(y);
else if(op == 2) t[now].s.reset(y);
else if(op == 3) t[now].s.flip();
int op = t[now].s.test(1004);///是否为1
t[now].w = t[now].s.count() - (1005-m)*op;
return ;
}
if(x <= mid) Insert(t[now].l,t[pre].l,l,mid,x,y,op);
else Insert(t[now].r,t[pre].r,mid+1,r,x,y,op);
int ls = t[now].l,rs = t[now].r;
t[now].w = t[ls].w + t[rs].w;
}
int main(){
read(n);read(m);read(p);
for(int i=1;i<=p;i++){
int op,x,y;
read(op);read(x);
if(op == 1){
read(y);
Insert(root[i],root[i-1],1,n,x,y,1);
}
else if(op == 2){
read(y);
Insert(root[i],root[i-1],1,n,x,y,2);
}else if(op == 3) Insert(root[i],root[i-1],1,n,x,0,3);
else root[i] = root[x];
di(t[root[i]].w);
}
return 0;
}
/***
6 3
1
2 aa
2 bb
1
2 aa
2 cc
***/