Cod sursa(job #2917137)

Utilizator mircea_007Mircea Rebengiuc mircea_007 Data 3 august 2022 15:17:02
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.52 kb
// This program was written by Mircea Rebengiuc
// on 02.08.2022
// for problem heavypath

#include <stdio.h>
#include <ctype.h>

#include <vector>

FILE *fin, *fout;

static inline int fgetint(){
  int n = 0, ch;

  while( !isdigit( ch = fgetc( fin ) ) );
  do
    n = n * 10 + ch - '0';
  while( isdigit( ch = fgetc( fin ) ) );

  return n;
}

static inline int max( int a, int b ){ return a > b ? a : b; }

#define MAXN 100000
#define MAXP2 131072
#define INF 2000000000
#define NIL -1

std::vector<int> adj[MAXN]; // lista de adiacenta
int par[MAXN];   // parinte
int depth[MAXN]; // adancime
int val[MAXN];   // valoare
//int size[MAXN];  // marimea subarborelui
int head[MAXN];  // capul lantului
int aintp[MAXN]; // indice in aint
int heavy[MAXN]; // fiul cel mai mare

char viz[MAXN];

// AINT implementation

int aint[2 * MAXP2];
int aintn;

int _query( int root, int rl, int rr, int ql, int qr ){
  int mij = (rl + rr) >> 1, left = 2 * root + 1, right = 2 * root + 2;

  if( rl == ql && qr == rr ) return aint[root];

  if( qr <= mij ) return _query( left, rl, mij, ql, qr );
  if( ql > mij ) return _query( right, mij+1, rr, ql, qr );

  return max(
    _query( left, rl, mij, ql, mij ),
    _query( right, mij+1, rr, mij+1, qr )
  );
}

// wrapper
inline __attribute__((always_inline)) int query( int ql, int qr ){
  if( ql > qr )
    return _query( 0, 0, aintn - 1, qr, ql );

  return _query( 0, 0, aintn - 1, ql, qr );
}

void update( int index, int newval ){// update is easier iterative
  int root = aintn - 1 + index;

  aint[root] = newval;

  while( root ){
    root = (root - 1) >> 1;
    aint[root] = max( aint[2 * root + 1], aint[2 * root + 2] );
  }
}

// returns subtree size
int initdfs( int root ){
  int maxsize = 0, csize, size = 1;

  for( int child : adj[root] )
    if( child != par[root] ){
      par[child] = root;
      depth[child] = 1 + depth[root];

      csize = initdfs( child );

      if( csize > maxsize ){
        heavy[root] = child;
        maxsize = csize;
      }

      size += csize;
    }

  return size;
}

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

  int n, q, i, op, a, b, qans;
  
  n = fgetint();
  q = fgetint();
  for( i = 0 ; i < n ; i++ )
    val[i] = fgetint();

  for( i = 1 ; i < n ; i++ ){
    a = fgetint() - 1;
    b = fgetint() - 1;

    adj[a].push_back( b );
    adj[b].push_back( a );
  }

  for( i = 0 ; i < n ; i++ )
    heavy[i] = NIL;

  depth[0] = head[0] = 0;
  par[0] = NIL;
  initdfs( 0 );

  b = 0;
  for( i = 0 ; i < n ; i++ )
    if( !viz[i] ){
      a = i;
      //printf( "heavychain:" );
      while( a != NIL ){
        viz[a] = 1;
        aintp[a] = b++;
        head[a] = i;// add head reference

        //printf( " %d(%d)", a + 1, head[a] + 1 );
        a = heavy[a];
      }
      //printf( "\n" );
    }

  aintn = 1;
  while( aintn < n )
    aintn <<= 1;

  for( i = 0 ; i < n ; i++ )
    update( aintp[i], val[i] );

  for( ; q-- ; ){
    op = fgetint();
    a = fgetint() - 1;
    b = fgetint() - 1;

    if( op ){// query
      qans = 0;
      while( head[a] != head[b] ){
        if( depth[head[a]] > depth[head[b]] ){
          qans = max( qans, query( aintp[head[a]], aintp[a] ) );
          a = par[head[a]];
        }else{
          qans = max( qans, query( aintp[head[b]], aintp[b] ) );
          b = par[head[b]];
        }
      }

      qans = max( qans, query( aintp[a], aintp[b] ) );

      fprintf( fout, "%d\n", qans );
    }else{
      b++;
      val[a] = b;
      update( aintp[a], b );
    }
  }

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