社区讨论

如果您 60 RE #1 #2 #3 #6情况6

P3302[SDOI2013] 森林参与者 3已保存回复 2

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
2 条
当前快照
1 份
快照标识符
@lr1eb3du
此快照首次捕获于
2024/01/06 09:37
2 年前
此快照最后确认于
2024/01/06 12:30
2 年前
查看原帖
如果您和我的写法类似,都在连边时将小的那棵树 dfs 删除主席树,那么请注意此时可能出现一个点被删除多次的情况。
我的写法:
CPP
inline int newnode() {
    if(top) {
        int x = stk[top--];
        return x;
    }
    else return ++cnt;
}

inline void del(int& o) {
    t[o].val = 0;
    //注意这里是直接删除,然后放进垃圾桶里的
    stk[++top] = o;
    o = 0;
}

inline void delnode(int& o) {
    if(t[o].ls) delnode(t[o].ls);
    if(t[o].rs) delnode(t[o].rs);
    del(o);
}

inline void deltree(int u, int f) {
    for(int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if(v == f) continue;
        deltree(v, u);
    }
    delnode(root[u]);
}
由于主席树上一个点可能被公用多次,因此可能被删除多次,这样会使后面的更新中发生错误。
因此要记录一下每个点是否已经被删除。如果已经被删除,那就不用放进栈里了。可以用一个 visvis 数组实现。
正确写法:
CPP
inline int newnode() {
    if(top) {
        int x = stk[top--];
        //
        vis[x] = false;
        //
        return x;
    }
    else return ++cnt;
}

inline void del(int& o) {
    t[o].val = 0;
    //注意这里
    if(!vis[o]) vis[o] = true, stk[++top] = o;
    //
    o = 0;
}

inline void delnode(int& o) {
    if(t[o].ls) delnode(t[o].ls);
    if(t[o].rs) delnode(t[o].rs);
    del(o);
}

inline void deltree(int u, int f) {
    for(int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if(v == f) continue;
        deltree(v, u);
    }
    delnode(root[u]);
}

回复

2 条回复,欢迎继续交流。

正在加载回复...