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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值