Cod sursa(job #3039005)

Utilizator ezluciPirtac Eduard ezluci Data 27 martie 2023 23:39:04
Problema Heavy Path Decomposition Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.62 kb
// solutie care foloseste longest 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 e[2*nMAX], k;
int rmq[17+1][2*nMAX];
int st[nMAX + 1];

int lung[nMAX + 1]; // lung[i] = lungimea celui mai lung lant de la i in jos
int nex[nMAX + 1]; // nex[i] = fiul care duce la aceasta lungime (lung[i])
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;
   e[++k] = nod;
   st[nod] = k;
   for (int fiu : gf[nod])
   {
      if (fiu == dad)
         continue;
      
      dfs(fiu, nod);
      e[++k] = nod;

      if (lung[fiu] + 1 > lung[nod])
      {
         lung[nod] = lung[fiu] + 1;
         nex[nod] = fiu;
      }
   }
}

void dfsDecompose(int nod, vector<int> &p, int dad = 0)
{
   p.pb(nod);

   for (int fiu : gf[nod])
   {
      if (fiu == dad)
         continue;
      
      if (nex[nod] == fiu)
      {
         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]);
}



void genRMQ()
{
   for (int i = 1; i < 2*n; ++i)
      rmq[0][i] = e[i];
   for (int j = 1; (1<<j) < 2*n; ++j)
      for (int i = 1; i-1 + (1<<j) < 2*n; ++i)
      {
         int a = rmq[j-1][i];
         int b = rmq[j-1][i + (1<<j-1)];
         
         if (niv[a] <= niv[b])
            rmq[j][i] = a;
         else
            rmq[j][i] = b;
      }
}

int queryRMQ(int l, int r)
{
   int log = 31 - __builtin_clz(r-l+1);
   int a = rmq[log][l];
   int b = rmq[log][r+1 - (1<<log)];
   
   if (niv[a] <= niv[b])
      return a;
   return b;
}

int LCA(int x, int y)
{
   if (st[x] > st[y])
      return queryRMQ(st[y], st[x]);
   return queryRMQ(st[x], st[y]);
}


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);
   genRMQ();

   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--)
   {// cerr << '\n';
      int op, x, y;
      cin >> op >> x >> y;

      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)
      {
         int lca = LCA(x, y);
// cerr << "BIGQUERY " << x << ' ' << y << '\n';
         auto solve = [&](int x, int y) -> int { // x e stramos al lui y
            int ans = 0;
// cerr << "query: " << x << ' ' << y << '\n';
            while (y)
            {
               int first = firstNodeInPath[y];
               
               if (niv[first] >= niv[x])
               {
                  // cerr << "first " << first << "  full " << y << " qaint 1 " << niv[y] - niv[first] + 1 << "  ans: " << queryAint(aint[first], 1, 1, path[first].size(),
                        //1, niv[y] - niv[first] + 1) <<  '\n';
                  ans = max(ans, queryAint(aint[first], 1, 1, path[first].size(),
                        1, niv[y] - niv[first] + 1));
                  y = tat[first];
               }
               else
               {
                  //cerr << "part " << y << " qaint " << niv[x] - niv[first] + 1 << ' ' << niv[y] - niv[first] + 1 << "  ans: " << queryAint(aint[first], 1, 1, path[first].size(),
                        //niv[x] - niv[first] + 1, niv[y] - niv[first] + 1) <<  '\n';
                  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';
      }
   }
}