Cod sursa(job #2643553)

Utilizator euyoTukanul euyo Data 20 august 2020 13:45:01
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.1 kb
#include <fstream>
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

ifstream fin( "heavypath.in" );
ofstream fout( "heavypath.out" );

const int MaxN = 100002;

struct TreeNode {
  int val, path, pos;
} data[MaxN]; 
//informatii pentru noduri

int subt[MaxN];
//subt[node] = greutatea arborelui de sub node
vector<int> T[MaxN];
//arborele
vector<int> path[MaxN];
//path[i] = nodurile de pe lantul i
int viz[MaxN];
int dimPath[MaxN], nextNodePath[MaxN];
//dimensiunea lantului
//tatal ultimului nod din lant  

//--------------------arborii de intervale-------------------

int segT[5 * MaxN];
//arborii de intervale pentru lanturi
int gapPath[MaxN];
//decalajul pentru fiecare lant in parte

int gap; //(este defapt gapPath[segPath])
//decalajul pentru arborele de intervale coresp. lantului accesat acum din segT
int segPath;
//lantul accesat acum in segT

void build( int node, int st, int dr ) {
  int mij = (st + dr) / 2;

  if ( st == dr ) {
    segT[node + gap] = data[path[segPath][st - 1]].val;
	return;  
  }
  build( 2 * node, st, mij );
  build( 2 * node + 1, mij + 1, dr );
  segT[node + gap] = max( segT[2 * node + gap], segT[2 * node + 1 + gap] );
}

int upos, uval;
//pozitia ce trebuie schimbata din lantul accesat acum
//si valoarea ce trebuie pusa in locul ei

void update( int node, int st, int dr ) {
  int mij = (st + dr) / 2;

  if ( st == dr ) {
    segT[node + gap] = uval;
    return;
  }
  if ( upos <= mij ) {
    update( 2 * node, st, mij );
  } else {
    update( 2 * node + 1, mij + 1, dr );
  }
  segT[node + gap] = max( segT[2 * node + gap], segT[2 * node + 1 + gap] );
}

int a, b;
//nodurile din segPath pe care se face query 

int query( int node, int st, int dr ) {
  int mij = (st + dr) / 2, x = 0, y = 0;

  if ( a <= st && dr <= b ) {
    return segT[node + gap];
  }
  if ( a <= mij ) {
    x = query( 2 * node, st, mij );
  }
  if ( b > mij ) {
    y = query( 2 * node + 1, mij + 1, dr );
  }
  return max( x, y );
}

//-------------------------impartirea in lanturi (DFS-uri)----------------------

//calculam greutatea nodurilor
int calcSubT( int node ) {
  subt[node] = viz[node] = 1;
  for ( int i = 0; i < (int)T[node].size(); ++i ) {
	if ( !viz[T[node][i]] ) {
	  subt[node] += calcSubT( T[node][i] );
	}
  }
  return subt[node];
}

int npath;
//lantul curent

void buildPaths( int node ) {
  int mxNode = -1, mx = 0, currPath;
  
  viz[node] = 1;
  //selectam cel mai greu fiu
  for ( int i = 0; i < (int)T[node].size(); ++i ) {
	if ( !viz[T[node][i]] ) {
      if ( subt[T[node][i]] > mx ) {
	    mx = subt[T[node][i]];
		mxNode = T[node][i];
	  }
	  buildPaths( T[node][i] );
	}
  }
  //incheiem lanturile fiilor mai slabi
  for ( int i = 0; i < (int)T[node].size(); ++i ) {
	if ( T[node][i] != mxNode ) {
	  nextNodePath[data[T[node][i]].path] = node;
	}
  }
  if ( mxNode != -1 ) { //daca node nu este frunza
	//node data
    currPath = data[node].path = data[mxNode].path;
    data[node].pos = data[mxNode].pos + 1;

	//node path data
	path[currPath].push_back( node );
	++dimPath[currPath];
  } else {
	//node data
	currPath = data[node].path = npath++;
	data[node].pos = 1;
	
	//node path data
	path[currPath].push_back( node );
	++dimPath[currPath];
  }
}

//----------------------------codul principal (de folosire a functiilor)-----------------------------

void case0( int &x, int &y ) {
  if ( x == 0 ) {
    x = 1;
  }
  if ( y == 0 ) {
    y = 1;
  }
}

int main() {
  int n, m, i, tp, x, y, maxXYpath;

  fin >> n >> m;
  for ( i = 1; i <= n; ++i ) {
	fin >> data[i].val;
  }
  for ( i = 1; i < n; ++i ) {
	fin >> x >> y;
	T[x].push_back( y );
	T[y].push_back( x );
  }
  calcSubT( 1 );
  for ( i = 1; i <= n; ++i ) {
    viz[i] = 0;  
  }
  buildPaths( 1 );
  nextNodePath[0] = 0;
  //calcularea gapPath
  for ( i = 0; i < npath; ++i ) {
	gapPath[i] = gapPath[i - 1] + 4 * dimPath[i - 1] + 1; //4 * dimPath[i - 1] = cat este nevoie pentru arborele de intervale al lantului i-1
    gap = gapPath[i];
	segPath = i;
	build( 1, 1, dimPath[i] );
  }
  //executarea operatiilor
  while ( m-- ) {
    fin >> tp >> x >> y;
	if ( tp == 0 ) { //update
      upos = data[x].pos;
	  uval = y;
	  gap = gapPath[data[x].path];
	  segPath = data[x].path;
	  update( 1, 1, dimPath[data[x].path] );
	} else { //query
	  maxXYpath = 0;
	  while ( data[x].path != data[y].path ) {
		case0( x, y );
		//x path query
		gap = gapPath[data[x].path];
		segPath = data[x].path;
        a = data[x].pos;
		b = dimPath[data[y].path];
        maxXYpath = max( maxXYpath, query( 1, 1, dimPath[data[x].path] ) );
        
		//y path query
		gap = gapPath[data[y].path];
		segPath = data[y].path;
		a = data[y].pos;
		b = dimPath[data[y].path];
		maxXYpath = max( maxXYpath, query( 1, 1, dimPath[data[y].path] ) );

		//trecem la urmatoarele lanturi cu nodurile coresp. 
		x = nextNodePath[data[x].path];
		y = nextNodePath[data[y].path];
	  }
	  case0( x, y );
	  gap = gapPath[data[x].path];
	  segPath = data[x].path;
	  a = min( data[x].pos, data[y].pos );
	  b = max( data[x].pos, data[y].pos );
      maxXYpath = max( maxXYpath, query( 1, 1, dimPath[data[x].path] ) );
	  fout << maxXYpath << "\n";
	}
  }
  fin.close();
  fout.close();
  return 0;
}