Cod sursa(job #3283448)

Utilizator mircea_007Mircea Rebengiuc mircea_007 Data 9 martie 2025 16:32:26
Problema Paduri de multimi disjuncte Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.3 kb
#include <stdio.h>
#include <ctype.h>

int nextc() {
  int ch;
  while( isspace( ch = fgetc( stdin ) ) );
  return ch;
}

#include <assert.h>
#include <vector>

using ll = long long;

struct Splay {
  struct Node {
    int c[2], par;
    // int key;

    // int siz;
    // ll sum;

    bool flip;

    Node(): par(0), flip(false) { c[0] = c[1] = 0; }
  };

  std::vector<Node> t;
  Splay( int n ): t(n + 1) {}

  // these would have been member functions of Node in pointer implementation
  void push_flip( int u ) {
    if( !u ) return;
    t[u].flip ^= 1;
  }

  void push( int u ) {
    int left = t[u].c[0];
    int right = t[u].c[1];

    if( t[u].flip ){
      std::swap( t[u].c[0], t[u].c[1] );
      std::swap( left, right );
      t[u].flip = false;

      push_flip( left );
      push_flip( right );
    }
  }

  // u is already pushed
  void pull( int u ) {} // nothing to pull in dsu

  int side( int u ) {
    int p = t[u].par;
    if( t[p].c[0] == u ) return 0;
    if( t[p].c[1] == u ) return 1;
    return -1;
  }

  void link( int p, int u, int side ) {
    push( p );
    
    if( u ) t[u].par = p;
    if( p ){
      t[p].c[side] = u;
      pull( p );
    }
  }

  // totul trebuie push-uit inainte de apel
  void zig( int x ) {
    int y = t[x].par;
    int s = side( x );
    // assert( s == 0 || s == 1 );

    int mij = t[x].c[s ^ 1];
    int up = t[y].par, sup = side( y );

    link( y, mij, s );
    link( x, y, s ^ 1 );
    link( up, x, sup );
  }

  void splay( int x ) {
    // assert( x ); // should never splay null
    
    while( side( x ) >= 0 ) {
      int y = t[x].par;
      if( side( y ) < 0 ){
        push( y );
        push( x );
        zig( x );
        continue;
      }

      int z = t[y].par;
      push( z );
      push( y );
      push( x );

      int sx = side( x );
      int sy = side( y );
      zig( sx == sy ? y : x );
      zig( x );
    }
  }
};

// nice trick:
//  instead of maintaining trans-chain links
//  a node may have a parent but not be its child
struct LinkCut : Splay {
  LinkCut( int n ): Splay(n + 1) {}

  // top of chain
  int leftmost( int u ) {
    push( u );
    while( t[u].c[0] )
      push( u = t[u].c[0] );
    return u;
  }

  // forces path decomposition to contain a chain strictly from the root to u and splays u
  void expose( int uu ) {
    int u = uu, prev = 0; // dreapta lui u va fi castrata si lasata asa
    while( u ){
      splay( u );

      // castram dreapta
      push( u );
      t[u].c[1] = prev;
      pull( u );

      prev = u;
      u = t[u].par;
    }
    splay( uu );
  }

  void reroot( int u ) {
    expose( u );
    push_flip( u );
  }

  int Root( int u ) {
    expose( u );
    return leftmost( u );
  }

  bool Same( int u, int v ) {
    return Root( u ) == Root( v );
  }

  void Link( int u, int v ) {
    expose( v );

    reroot( u );
    t[u].par = v; // trans-chain edge
    pull( v );
  }

  // void Cut( int u, int v ) {
  // }
};

int main() {
  FILE *fin = fopen( "disjoint.in", "r" );
  FILE *fout = fopen( "disjoint.out", "w" );

  int n, q;
  fscanf( fin, "%d%d", &n, &q );

  LinkCut zile(n);
  for( int i = 0; i < q; i++ ){
    int task, a, b;
    fscanf( fin, "%d%d%d", &task, &a, &b );

    if( task == 1 )
      zile.Link( a, b );
    else
      fputs( zile.Same( a, b ) ? "DA\n" : "NU\n", fout );
  }

  fclose( fin );
  fclose( fout );
  return 0;
}