Cod sursa(job #2916375)

Utilizator andreic06Andrei Calota andreic06 Data 29 iulie 2022 15:47:41
Problema Heavy Path Decomposition Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.81 kb
#include <bits/stdc++.h>

using namespace std;
const int INF = 2e9;
const int NMAX = 1e5;
const int LOG_MAX = 17;
const int ROOT = 1;
const int PARENT = 0;
const int NULL_COST = 0;


class InParser {
private:
	FILE *fin;
	char *buff;
	int sp;

	char read_ch() {
		++sp;
		if (sp == 4096) {
			sp = 0;
			fread(buff, 1, 4096, fin);
		}
		return buff[sp];
	}

public:
	InParser(const char* nume) {
		fin = fopen(nume, "r");
		buff = new char[4096]();
		sp = 4095;
	}

	InParser& operator >> (int &n) {
		char c;
		while (!isdigit(c = read_ch()) && c != '-');
		int sgn = 1;
		if (c == '-') {
			n = 0;
			sgn = -1;
		} else {
			n = c - '0';
		}
		while (isdigit(c = read_ch())) {
			n = 10 * n + c - '0';
		}
		n *= sgn;
		return *this;
	}

	InParser& operator >> (long long &n) {
		char c;
		n = 0;
		while (!isdigit(c = read_ch()) && c != '-');
		long long sgn = 1;
		if (c == '-') {
			n = 0;
			sgn = -1;
		} else {
			n = c - '0';
		}
		while (isdigit(c = read_ch())) {
			n = 10 * n + c - '0';
		}
		n *= sgn;
		return *this;
	}
};
InParser in ( "heavypath.in" );
ofstream out ( "heavypath.out" );


struct define_edge {
    int from, to;
    ///int cost;
}; vector<define_edge> tree[1 + NMAX];
int father[1 + NMAX], instant_cost[1 + NMAX];
int depth[1 + NMAX], size_of[1 + NMAX];
int n, q;

void dfs ( int p, int root ) {
   depth[root] = depth[p] + 1;
   father[root] = p;

   for ( auto edge : tree[root] ) {
      int child = edge.to;
      if ( child != p )
        dfs ( root, child );
   }

   size_of[root] = 1;
   for ( auto edge : tree[root] ) {
      int child = edge.to;
      if ( child != p )
        size_of[root] += size_of[child];
   }
}

int parent[1 + LOG_MAX][1 + NMAX];
class Lowest_Common_Ancestor {
    public :
       void init ();
       int query ( int u, int v );
} LCA;
void Lowest_Common_Ancestor :: init () {
    for ( int node = 1; node <= n; node ++ )
       parent[0][node] = father[node];
    for ( int pwr = 1; (1 << pwr) <= n; pwr ++ )
       for ( int node = 1; node <= n; node ++ )
          parent[pwr][node] = parent[pwr - 1][parent[pwr - 1][node]];
}
int Lowest_Common_Ancestor :: query ( int u, int v ) {
   if ( depth[u] < depth[v] )
     swap ( u, v );
   for ( int pwr = LOG_MAX; pwr >= 0; pwr -- )
      if ( depth[parent[pwr][u]] >= depth[v] )
        u = parent[pwr][u];
   for ( int pwr = LOG_MAX; pwr >= 0; pwr -- )
      if ( parent[pwr][u] != parent[pwr][v] ) {
        u = parent[pwr][u];
        v = parent[pwr][v];
      }

   if ( u == v )
     return u;
   return father[u];
}

int sgtree[1 + 4 * NMAX];
class SegTree {
   public :
      void update ( int node, int left, int right, int pos, int new_value );
      int query ( int node, int left, int right, int qleft, int qright );
      static inline int merge__ ( int first, int second );
} ST;

int SegTree :: merge__ ( int first, int second ) {
    return max ( first, second );
}
void SegTree :: update ( int node, int left, int right, int pos, int new_value ) {
   if ( left == right )
     sgtree[node] = new_value;
   else {
     int mid = left + (right - left) / 2;
     if ( pos <= mid )
       update ( node * 2, left, mid, pos, new_value );
     else
       update ( node * 2 + 1, mid + 1, right, pos, new_value );
     sgtree[node] = merge__ (sgtree[node * 2], sgtree[node * 2 + 1]);
   }
}
int SegTree :: query ( int node, int left, int right, int qleft, int qright ) {
   if ( qleft <= left && right <= qright )
     return sgtree[node];
   int mid = left + (right - left) / 2;

   int answer = -INF;
   if ( qleft <= mid )
     answer = merge__ ( answer, query (node * 2, left, mid, qleft, qright) );
   if ( mid + 1 <= qright )
     answer = merge__ ( answer, query (node * 2 + 1, mid + 1, right, qleft, qright) );
   return answer;
}

bool heavy[1 + NMAX]; /// muchia node-parinte este heavy
int b[1 + NMAX], e[1 + NMAX]; /// nodul de inceput si sfarsit al path-urilor
int chain_indx[1 + NMAX]; int k = 0; /// in ce path se afla nodul x
int pos[1 + NMAX]; /// pozitia in segtree a nodului x

class Heavy_Light_Decomposition  {
   public :
      void dfs_chain ( int p, int root );
      void construct_chain ();
      void update ( int node, int new_value );
      int query ( int u, int v );
} HLD;

void Heavy_Light_Decomposition :: dfs_chain ( int p, int root ) {
   for ( auto edge : tree[root] ) {
      int child = edge.to;
      if ( child != p ) {
        if ( size_of[child] > size_of[root] / 2 )
          heavy[child] = true;
        else
          heavy[child] = false;
        dfs_chain ( root, child );
      }
   }

   bool all_light = true;
   for ( auto edge : tree[root] ) {
      int child = edge.to;
      if ( child != p && heavy[child] == true )
        all_light = false;
   }
   if ( all_light == true )
     b[++ k] = root;
}
void Heavy_Light_Decomposition :: construct_chain () {
   int curr_pos = 0;
   for ( int indx = 1; indx <= k; indx ++ ) {
      int node = b[indx]; chain_indx[node] = indx;
      pos[node] = ++ curr_pos;
      while ( heavy[node] == true ) {
         node = father[node];
         chain_indx[node] = indx;
         pos[node] = ++ curr_pos;
      }
      e[indx] = node;
   }
}

void Heavy_Light_Decomposition :: update ( int node, int new_value ) {
   ST.update ( 1, 1, n, pos[node], new_value );
}
int Heavy_Light_Decomposition :: query ( int u, int v ) {
  int answer = -INF;
  int bridge = LCA.query ( u, v );
  ///cout << bridge << "\n";

  int start = u;
  for ( int step = 0; step < 2; step ++, start = v ) {
     int node = start;
     while ( chain_indx[node] != chain_indx[bridge] ) {
       answer = max ( answer, ST.query ( 1, 1, n, pos[node], pos[e[chain_indx[node]]] ) );
       node = father[e[chain_indx[node]]];
    }
    answer = max ( answer, ST.query ( 1, 1, n, pos[node], pos[bridge] ) );
  }
  return answer;
}
int main()
{

   in >> n >> q;
   for ( int node = 1; node <= n; node ++ )
      in >> instant_cost[node];
   for ( int indx = 1; indx < n; indx ++ ) {
      int u, v; in >> u >> v;
      tree[u].push_back ( {u, v, } );
      tree[v].push_back ( {v, u} );
   }

   dfs ( PARENT, ROOT ); LCA.init ();
   HLD.dfs_chain ( PARENT, ROOT ); HLD.construct_chain ();

   /**cout << k << "\n";
   for ( int indx = 1; indx <= n; indx ++ )
      cout << b[indx] << " " << e[indx] << "\n";**/

   for ( int node = 1; node <= n; node ++ )
      HLD.update ( node, instant_cost[node] );
   for ( int indx = 1; indx <= q; indx ++ ) {
      int task; in >> task;
      if ( task == 0 ) {
        int node, new_value; in >> node >> new_value;
        HLD.update ( node, new_value );
      }
      else {
        int u, v; in >> u >> v;
        out << HLD.query ( u, v ) << "\n";
      }
   }


    return 0;
}