Cod sursa(job #3173416)

Utilizator raileanu-alin-gabrielRaileanu Alin-Gabriel raileanu-alin-gabriel Data 22 noiembrie 2023 21:08:11
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.48 kb
#include <fstream>
#include <vector>
#include <set>
const int LOG=17;
const int NMAX=100005;

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

struct date
{
  int c, st, dr;
};
vector<date> ans;
set<pair<int, int>, greater<pair<int, int>>> hv[NMAX];
set<pair<int, int>> s;
vector <int> v[NMAX], path[NMAX];
pair<int, int> pth[NMAX], intt[NMAX];
int val[NMAX], poz[NMAX], sz[NMAX];
int niv[NMAX], in[NMAX], out[NMAX], w[NMAX];
int dp[LOG][NMAX], aint[2*NMAX];
int n, q, nrp, cnt;

void build(int, int, int);
void update(int, int, int, int, int);
int query(int, int, int, int, int);
void build_lca();
void dfs1(int);
bool is_anc(int, int);
int lca(int, int);
void dfs2(int, int);
void decomp();
void ord();
int query_hpd(int, int);
void update_hpd(int, int);
int qrry(int, int);

int main()
{
  int i, tip, a, b;
  fin>>n>>q;
  for(i=1; i<=n; i++) fin>>w[i];
  for(i=1; i<n; i++)
  {
    fin>>a>>b;
    v[a].push_back(b);
    v[b].push_back(a);
  }
  dfs1(1);
  build_lca();
  dfs2(1, 1);
  decomp();
  ord();
  /*for(i=1; i<=n; i++)
  {
    fout<<i<<" -> path: "<<pth[i].first<<" poz: "<<pth[i].second<<'\n';
  }
  for(i=1; i<=n; i++)
  {
    fout<<i<<" -> poz: "<<poz[i]<<'\n';
  }*/
  for(i=1; i<=q; i++)
  {
    fin>>tip>>a>>b;
    if(tip==0) update_hpd(a, b);
    else fout<<query_hpd(a, b)<<'\n';
  }
  return 0;
}

void update_hpd(int nod, int val)
{
  update(1, 1, n, poz[nod], val);
}

int query_hpd(int a, int b)
{
  int maxim, lcaa;
  lcaa=lca(a, b);
  //fout<<a<<' '<<b<<' '<<lcaa<<'\n';
  if(lcaa==a) return qrry(a, b);
  if(lcaa==b) return qrry(b, a);
  maxim=max(qrry(lcaa, a), qrry(lcaa, b));
  return maxim;
}

int qrry(int a, int b)
{
  ans.clear();
  while(true)
  {
    if(pth[a].first==pth[b].first)
    {
      ans.push_back({pth[b].first, poz[a], poz[b]});
      break;
    }
    else ans.push_back({pth[b].first, poz[path[pth[b].first][0]], poz[b]});
    b=dp[0][path[pth[b].first][0]];
  }
  int maxim=0;
  for(auto i:ans) maxim=max(maxim, query(1, 1, n, i.st, i.dr));
  return maxim;
}

void ord()
{
  int i, nr=0;
  for(i=1; i<=nrp; i++)
  {
    for(auto j:path[i])
    {
      ++nr;
      val[nr]=w[j];
      poz[j]=nr;
    }
    intt[i]=make_pair(poz[path[i][0]], poz[path[i][path[i].size()-1]]);
  }
  build(1, 1, n);
}

void decomp()
{
  int nod;
  pair<int, int> p;
  while(!s.empty())
  {
    ++nrp;
    p=(*s.begin());
    nod=p.second;
    while(true)
    {
      //l-am adaugat in path-ul nrp
      path[nrp].push_back(nod);
      pth[nod]=make_pair(nrp, path[nrp].size());
      //il elimin din arbore
      hv[dp[0][nod]].erase(make_pair(sz[nod], nod));
      s.erase(make_pair(niv[nod], nod));
      if(hv[nod].empty()) break;
      p=(*hv[nod].begin());
      nod=p.second;
    }
  }
}

void dfs2(int nod, int lvl)
{
  sz[nod]=1;
  niv[nod]=lvl;
  for(auto i:v[nod])
  {
    if(!sz[i])
    {
      dfs2(i, lvl+1);
      sz[nod]+=sz[i];
      hv[nod].insert(make_pair(sz[i], i));
    }
  }
  s.insert(make_pair(niv[nod], nod));
}

int lca(int a, int b)
{
  int j;
  if(a==b || is_anc(a, b)) return a;
  if(is_anc(b, a)) return b;
  for(j=LOG; j>=0; j--)
  {
    if(!is_anc(dp[j][a], b) && dp[j][a]!=0)
      a=dp[j][a];
  }
  return dp[0][a];
}

bool is_anc(int a, int b)
{
  return (in[a]<=in[b] && out[b]<=out[a]);
}

void dfs1(int nod)
{
  in[nod]=++cnt;
  for(auto i:v[nod])
  {
    if(!in[i])
    {
      dp[0][i]=nod;
      dfs1(i);
    }
  }
  out[nod]=++cnt;
}

void build_lca()
{
  int i, j;
  for(j=1; j<=LOG; j++)
  {
    for(i=1; i<=n; i++)
    {
      dp[j][i]=dp[j-1][dp[j-1][i]];
    }
  }
}

void build(int nod, int st, int dr)
{
  if(st==dr)
  {
    aint[nod]=val[st];
    return;
  }
  int mij=(st+dr)/2;
  build(2*nod, st, mij);
  build(2*nod+1, mij+1, dr);
  aint[nod]=max(aint[2*nod], aint[2*nod+1]);
}

void update(int nod, int st, int dr, int poz, int val)
{
  if(st==dr)
  {
    aint[nod]=val;
    return;
  }
  int mij=(st+dr)/2;
  if(poz<=mij) update(2*nod, st, mij, poz, val);
  else update(2*nod+1, mij+1, dr, poz, val);
  aint[nod]=max(aint[2*nod], aint[2*nod+1]);
}

int query(int nod, int st, int dr, int qst, int qdr)
{
  if(st>=qst && dr<=qdr) return aint[nod];
  int mij=(st+dr)/2, maxim=0;
  if(qst<=mij) maxim=max(maxim, query(2*nod, st, mij, qst, qdr));
  if(qdr>mij) maxim=max(maxim, query(2*nod+1, mij+1, dr, qst, qdr));
  return maxim;
}