【Codeforces 707D】Persistent Bookcase | 主席树、bitset

题目大意:

给出一个 n ∗ m n*m nm的矩阵,需要对其进行下列操作:

  • 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 100000log(1000)1000/32=100000010=10000000
这是完全可以的

所以时间复杂度也同样为: O ( q ∗ l o g ( 1000 ) ∗ 1000 / 32 ) O(q*log(1000)*1000/32) O(qlog(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
***/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/112459321
今日推荐