Cod sursa(job #3039128)

Utilizator ezluciPirtac Eduard ezluci Data 28 martie 2023 10:47:17
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.23 kb
// solutie care foloseste heavy path decomposition

using namespace std;
#ifdef EZ
   #include "./ez/ez.h"
   const string FILE_NAME = "test";
#else
   #include <bits/stdc++.h>
   const string FILE_NAME = "heavypath";
#endif
#define mp make_pair
#define mt make_tuple
#define ll long long
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define cin fin
#define cout fout
ifstream fin (FILE_NAME + ".in");
ofstream fout (FILE_NAME + ".out");

const int nMAX = 100e3;

int n, m;
int v[nMAX + 1];
vector<int> gf[nMAX + 1];
int tat[nMAX + 1];
int niv[nMAX + 1];

int subarbNods[nMAX + 1]; // cate noduri are un subarbore
vector<int> path[nMAX + 1];
vector<int> aint[nMAX + 1];
int firstNodeInPath[nMAX + 1];


void dfs(int nod, int dad = 0)
{
   niv[nod] = niv[dad] + 1;
   tat[nod] = dad;
   subarbNods[nod]++;

   for (int fiu : gf[nod])
   {
      if (fiu == dad)
         continue;
      
      dfs(fiu, nod);
      subarbNods[nod] += subarbNods[fiu];
   }
}

void dfsDecompose(int nod, vector<int> &p, int dad = 0)
{
   p.pb(nod);
   
   int max = 0, i;
   for (int fiu : gf[nod])
   {
      if (fiu == dad)
         continue;
      
      if (subarbNods[fiu] > max)
      {
         max = subarbNods[fiu];
         i = fiu;
      }
   }

   for (int fiu : gf[nod])
   {
      if (fiu == dad)
         continue;
      
      if (fiu == i)
      {
         firstNodeInPath[fiu] = firstNodeInPath[nod];
         dfsDecompose(fiu, p, nod);
      }
      else
      {
         firstNodeInPath[fiu] = fiu;
         dfsDecompose(fiu, path[fiu], nod);
      }
   }
}


void buildAint(int which, int nod, int st, int dr)
{
   vector<int> &Aint = aint[which];
   vector<int> &V = path[which];

   if (st == dr)
      return (void) (Aint[nod] = v[V[st-1]]);
   
   int mj = st+dr >> 1;
   buildAint(which, nod<<1, st, mj);
   buildAint(which, nod<<1|1, mj+1, dr);
   Aint[nod] = max(Aint[nod<<1], Aint[nod<<1|1]);
}

int queryAint(vector<int> &aint, int nod, int st, int dr, int qst, int qdr)
{
   if (qst <= st && dr <= qdr)
      return aint[nod];
   
   int mj = st+dr >> 1;
   int ans = 0;
   if (qst <= mj)
      ans = max(ans, queryAint(aint, nod<<1, st, mj, qst, qdr));
   if (mj+1 <= qdr)
      ans = max(ans, queryAint(aint, nod<<1|1, mj+1, dr, qst, qdr));
   
   return ans;
}

void updateAint(vector<int> &aint, int nod, int st, int dr, int qpos, int qval)
{
   if (st == dr)
      return (void) (aint[nod] = qval);
   
   int mj = st+dr >> 1;
   if (qpos <= mj)
      updateAint(aint, nod<<1, st, mj, qpos, qval);
   else
      updateAint(aint, nod<<1|1, mj+1, dr, qpos, qval);
   aint[nod] = max(aint[nod<<1], aint[nod<<1|1]);
}


int main()
{
   cin >> n >> m;
   for (int i = 1; i <= n; ++i)
      cin >> v[i];
   for (int i = 1; i < n; ++i)
   {
      int a, b;
      cin >> a >> b;
      gf[a].pb(b);
      gf[b].pb(a);
   }

   dfs(1);

   firstNodeInPath[1] = 1;
   dfsDecompose(1, path[1]);

   for (int i = 1; i <= n; ++i)
   {
      if (path[i].empty())
         continue;
      
      aint[i].resize(4 * path[i].size());
      buildAint(i, 1, 1, path[i].size());
   }

   while (m--)
   {
      int op, x, y;
      cin >> op >> x >> y;
//cerr << "\nQUERY " << op << ' ' << x << ' ' << y << '\n';
      if (op == 0)
      {
         int first = firstNodeInPath[x];
         v[x] = y;
         updateAint(aint[first], 1, 1, path[first].size(), niv[x] - niv[first] + 1, y);
      }

      else if (op == 1)
      {
         vector<int> tx, ty;

         for (int xc = x; xc; )
         {
            xc = firstNodeInPath[xc];
            xc = tat[xc];
            tx.pb(xc);
             //cerr << tx.back() << ' '; 
         } //cerr << '\n';
         for (int yc = y; yc; )
         {
            yc = firstNodeInPath[yc];
            yc = tat[yc];
            ty.pb(yc);
            //cerr << ty.back() << ' ';
         }
// cerr << '\n';
         int lca = 0;
         for (int i = tx.size()-1, j = ty.size()-1; i!=-1 && j!=-1; i--, j--)
         {
            if (tx[i] != ty[j])
            {
               if (niv[tx[i]] <= niv[ty[j]])
                  lca = tx[i];
               else
                  lca = ty[j];
               break;
            }
            else
               lca = tx[i];
         }
         if (lca == 0)
            lca = 1;
         
// cerr << "\nLCA OF " << x << ' ' << y << " IS " << lca << '\n';
         auto solve = [&](int x, int y) -> int { // x e stramos al lui y
            int ans = 0;

            while (y)
            {
               int first = firstNodeInPath[y];
               
               if (niv[first] >= niv[x])
               {
                  ans = max(ans, queryAint(aint[first], 1, 1, path[first].size(),
                        1, niv[y] - niv[first] + 1));
                  y = tat[first];
               }
               else
               {
                  ans = max(ans, queryAint(aint[first], 1, 1, path[first].size(),
                        niv[x] - niv[first] + 1, niv[y] - niv[first] + 1));
                  y = 0;
               }
            }

            return ans;
         };

         if (lca != x && lca != y)
            cout << max(solve(lca, x), solve(lca, y)) << '\n';
         else if (niv[x] <= niv[y])
            cout << solve(x, y) << '\n';
         else
            cout << solve(y, x) << '\n';
      }
   }
}