[可持久化线段树] codeforces 707D. Persistent Bookcase

D. Persistent Bookcase

题意:

一个 nm 矩阵 A ,维护4种操作:

  • 1 i j:把第 A[i][j] 赋值为1
  • 2 i j:把第 A[i][j] 赋值为0
  • 3 i:把 A[i] 的0变1,1变0
  • 4 i:回到第i个操作之后的状态

数据保证合法。
每个操作完成后输出整个矩阵1的个数。

思路:

一维的话就可持久化就好啦,二维的话就可持久化套可持久化就好啦。
对操作3稍加思考的话可以发现可以像其他操作一样 O(1) 的完成。
每次都是对整行操作,只需要打标记就好了,但是我们又不希望破坏复杂度,于是修改一下行线段树的节点含义,令其总是维护没有翻转时的值,这样操作3就不需要对行线段树进行任何操作。
但是操作1和操作2就需要考虑当前翻转的状态,如果是已经翻转,那么根据上面说的维护没有翻转时候的值,操作1就变成赋值0,算上翻转后实际状态就变成1了,操作2类似。
空间有点多,于是动态开点。
注意到这题不要求在线,那么其实离线也可以做,方法就是按时间线对操作建树dfs一遍,每次回到k会使k的时间线分裂(一切都是命运石之门的选择),其实还是棵树。

#include
using namespace std;
const int Q = 1e5+5;
int n, m, q;
struct nodeX{
    int v;
    nodeX *ls, *rs;
    nodeX(){ ls = rs = this; v = 0; }
    nodeX(nodeX *pre){ ls = pre->ls, rs = pre->rs, v = pre->v; }
}*NULLX = new nodeX;
void updateX(nodeX* &rt, nodeX* pre, int l, int r, int pos, int val){
    rt = new nodeX(pre);
    if(l == r){
        rt->v = val;
        return;
    }
    int mid = (l+r) >> 1;
    if(pos <= mid) updateX(rt->ls, pre->ls, l, mid, pos, val);
    else updateX(rt->rs, pre->rs, mid+1, r, pos, val);
    rt->v = rt->ls->v + rt->rs->v;
}
struct nodeY{
    int v, rev;
    nodeY *ls, *rs;
    nodeX *Xrt;
    nodeY(){ ls = rs = this; Xrt = NULLX; v = rev = 0; }
    nodeY(nodeY *pre){ ls = pre->ls, rs = pre->rs, Xrt = pre->Xrt; v = pre->v, rev = pre->rev; }
}*NULLY = new nodeY;
nodeY *rt[Q];
void updateY(nodeY* &rt, nodeY* pre, int l, int r, int pos1, int pos2, int op){
    rt = new nodeY(pre);
    if(l == r){
        if(op <= 2) updateX(rt->Xrt, pre->Xrt, 1, m, pos2, (op == 1)^rt->rev);
        if(op == 3) rt->rev^= 1;
        rt->v = rt->rev? m- rt->Xrt->v : rt->Xrt->v;
        return;
    }
    int mid = (l+r) >> 1;
    if(pos1 <= mid) updateY(rt->ls, pre->ls, l, mid, pos1, pos2, op);
    else updateY(rt->rs, pre->rs, mid+1, r, pos1, pos2, op);
    rt->v = rt->ls->v + rt->rs->v;
}
int main(){
    ios::sync_with_stdio(0); cin.tie(0);
    rt[0] = new nodeY();
    cin >> n >> m >> q;
    for(int i = 1; i <= q; ++i){
        int t, x, y;
        cin >> t >> x;
        if(t <= 2){
            cin >> y;
            updateY(rt[i], rt[i-1], 1, n, x, y, t);
        }
        else if(t == 3){
            updateY(rt[i], rt[i-1], 1, n, x, 0, t);
        }
        else if(t == 4){
            rt[i] = new nodeY(rt[x]);
        }
        cout << rt[i]->v << '\n';
    }
}

你可能感兴趣的:(ACM,题解)