D. Persistent Bookcase (可持久化线段树维护bitset)

传送门

给定一个n*m的矩阵,每个元素都是0或1,一共4种操作,操作q次。
1、把(i,j)改成1
2、把(i,j)改成0
3、翻转第i行
4.回溯变成第k次操作时的矩阵
每次操作完后输出矩阵所有元素之和。

(1<=n,m<=1000,q<=1e5)

涉及回溯历史版本,可持久化线段树。
我们把每行看成一个整体,单独一行涉及的操作是单点修改,区间反转,查询区间和,如果我们对每行都建线段树,即:用线段树维护n棵线段树之和,那么肯定会爆空间的。

单点修改,区间反转,查询区间和我们可以用一个空间位1000的bitset来实现。

理论上空间和时间都会缩小64倍。

即:
每个叶子节点开一个1000位的bitset,维护区间和,即:1的个数。

#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
const int maxn = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll inf = (ll)4e16+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){
    
    while(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
inline ll read()
{
    
    
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
    
    while(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){
    
    x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node 
{
    
    
    bitset<1005> col;
    int sum;
}tree[maxn*20];
int lc[maxn*20],rc[maxn*20];//nlogq的空间
int root[maxn],tot;
int n,m,q;
inline void pushup(int rt)
{
    
    
    tree[rt].sum=tree[lc[rt]].sum + tree[rc[rt]].sum;
}
inline void upd(int &rt,int last,int l,int r,int pos,int f,int j)
{
    
    
    rt=++tot;
    lc[rt]=lc[last],rc[rt]=rc[last];
    tree[rt]=tree[last];
    if(l==r) 
    {
    
    
        if(f==1) 
        {
    
    
            if(!tree[rt].col[j]) tree[rt].sum++;
            tree[rt].col.set(j,1);
 
        }
        else if(f==2) 
        {
    
    
            if(tree[rt].col[j]) tree[rt].sum--;
            tree[rt].col.set(j,0);
        }
        else 
        {
    
    
            tree[rt].col.flip();
            tree[rt].sum=m-tree[rt].sum;
        }
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) upd(lc[rt],lc[last],l,mid,pos,f,j);
    else upd(rc[rt],rc[last],mid+1,r,pos,f,j);
    pushup(rt);
}
int main()
{
    
    
    scanf("%d %d %d",&n,&m,&q);
    for(int i=1,f,i1,j,k;i<=q;i++)
    {
    
    
        scanf("%d",&f);
        if(f==1 || f==2 ) 
        {
    
    
            scanf("%d %d",&i1,&j);
            upd(root[i],root[i-1],1,n,i1,f,j);
        }
        else if(f==3) 
        {
    
    
            scanf("%d",&i1);
            upd(root[i],root[i-1],1,n,i1,f,0);
        }
        else 
        {
    
    
            scanf("%d",&k);
            root[i]=root[k];
        }
        printf("%d\n",tree[root[i]].sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46030630/article/details/121305844
今日推荐