Splay 求调样例死循环,悬赏 2 个关注,lz 调崩溃了/kk

P3391 【模板】文艺平衡树

AC_CSP @ 2023-03-03 17:55:55

# include <bits/stdc++.h>
using namespace std ;
const int N = 1e5 + 7 ;
const int INF = 0x3f3f3f3f ;
int rt , ch[N][2] , fa[N] , val[N] , cnt[N] , size[N] , tot , tag[N] ;
inline void upd_size ( int u ) { size[u] = cnt[u] + size[ch[u][0]] + size[ch[u][1]] ; }
inline bool get ( int u ) { return u == ch[fa[u]][1] ; }
inline void push_down ( int u ) {
    if ( u && tag[u] ) {
        tag[ch[u][0]] ^= 1 ;
        tag[ch[u][1]] ^= 1 ;
        swap ( ch[u][0] , ch[u][1] ) ;
        tag[u] = 0 ;
    }
}
inline void _rotate ( int x ) { 
    int y = fa[x] , z = fa[y] , opt = get ( x ) ;
    push_down ( x ) , push_down ( y ) ;
    ch[y][opt] = ch[x][opt ^ 1] ;
    if ( ch[x][opt ^ 1] ) fa[ch[x][opt ^ 1]] = y ;
    ch[x][opt ^ 1] = y ; fa[y] = x ; fa[x] = z ;
    if ( z ) ch[z][ get ( y ) ] = x; 
    upd_size ( y ) , upd_size ( x ) ;
}
inline void Splay ( int x , int to ) {
    for ( int f = fa[x] ; f = fa[x] , f != to ; _rotate ( x ) )
        if ( fa[f] != to ) _rotate ( get ( x ) == get ( f ) ? f : x ) ;
    // cout << "Error : " << x << "\n" ;
    if ( to == 0 ) rt = x ;
}
inline int find ( int x ) {
    int now = rt ;
    // cout << "begin :: find \n" ;
    while ( 1 ) {
        // cout << size[0] << " !!! \n" ;
        // cout << "Error _ now / x : " << now << " " << x << "\n" ;
        // cout << "Ch : " << ch[now][0] << " " << ch[now][1] << "\n" ;
        // cout << "Size : " << size[ch[now][0]] << "\n" ;
        push_down(now) ;
        if ( x <= size[ch[now][0]] ) now = ch[now][0] ;
        else{
            x -= size[ch[now][0]] + 1 ;
            if ( !x ) return now ;
            // cout << "enter right\n" ;
            now = ch[now][1] ;  
        }
    }
}
inline void reverse ( int x , int y ) {
    int l = x - 1 , r = y + 1 ;
    l = find ( l ) , r = find ( r ) ;
    Splay ( l , 0 ) , Splay ( r , l ) ;
    tag[ch[ch[rt][1]][0]] ^= 1 ;
}
inline void dfs ( int u ) {
    // cout << u << "\n" ;
    push_down(u) ;
    if ( ch[u][0] ) dfs ( ch[u][0] ) ;
    if ( val[u] != INF && val[u] != -INF ) cout << val[u] << " " ;
    if ( ch[u][1] ) dfs ( ch[u][1] ) ;
}
inline void insert ( int x ) {
    if ( !rt ) {
        rt = ++ tot ; val[tot] = x ; cnt[tot] = 1 ; size[tot] = 1 ;
        return ;
    }
    int now = rt , f = 0 ;
    while ( 1 ) {
        // cout << f << " " << now << "\n" ;
        f = now , now = ch[now][val[ch[now][0]] < x] ;
        // cout << "Error1\n" ;
        if ( !now ) {
            val[++tot] = x , cnt[tot] = 1 , size[tot] = 1 , fa[tot] = f , ch[f][val[f] < x] = now ;
            // cout << "Error2\n" ;
            // cout << cnt[1] << " " << size[1] << " " << ch[1][0] << " " << ch[1][1] << "\n" ;
            upd_size ( f ) ;
            // cout << "Error4\n" ;
            Splay ( tot , 0 ) ; break ;
        }
    }
}
int main () {
    int n , m ;
    // ios :: sync_with_stdio(false) ; cin . tie(0) , cout . tie(0) ;
    cin >> n >> m ;
    // cout << "here\n" ;
    insert ( INF ) , insert ( - INF ) ; // cout << "Error3\n" ;
    for ( int i = 1 ; i <= n ; i++ ) insert(i) ;
    // cout << "ereh\n" ;
    while ( m-- ) {
        // cout << size[0] << " 草 \n" ;
        int x , y ;
        cin >> x >> y ;
        reverse ( x + 1 , y + 1 ) ;
    }
    cout << rt ;
    dfs ( rt ) ;
    return 0 ;
}

by 2018ljw @ 2023-03-03 18:35:31

@AC_CSP

稍微用自己码风改写了一下,fx 就是 get 函数

void rotate(int x){
    int y=fa[x],z=fa[y],p=fx(x);
    pushdown(x);pushdown(y);
    son[y][p]=son[x][p^1];
    if(son[x][p^1])fa[son[x][p^1]]=y;
    son[x][p^1]=y;
    fa[y]=x;fa[x]=z;
    if(z)son[z][fx(y)]=x; 
    pushup(y),pushup(x);
}

前面都写的很对,但到 if(z)son[z][fx(y)]=x; 这步时,y 的信息已经更新完了,fx(y) 得到的已经不是原先 yz 的哪个儿子了。

把这句话提到 pushdown 下面即可。


by AC_CSP @ 2023-03-03 21:25:23

@2018ljw 感谢!顺便问个小问题,为什么先下放儿子再下放父亲,我怎么感觉先下放父亲才准确(


by AC_CSP @ 2023-03-03 21:25:52

@2018ljw 已经关注的人就不能关注第二次了qwq


by 2018ljw @ 2023-03-03 21:35:48

@AC_CSP

感觉都可以吧,正常来说 rotate x 的时候因为是从根出发的所以父亲应该已经访问过没有标记了


by AC_CSP @ 2023-03-03 21:48:15

@2018ljw 谢谢,明白了qwq


|