Cod sursa(job #1463404)

Utilizator ZeusCatalin Tiseanu Zeus Data 20 iulie 2015 21:36:11
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 15.24 kb
using namespace std;

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <array>

#include <sys/time.h>
#include <random>
#include <chrono>
#include <unordered_map>
#include <unordered_set>

#include <chrono>

using namespace std::chrono;

//#define DEBUG              // general information//

template<class T, class V> std::ostream&  operator <<(std::ostream& stream, const pair<T,V> & p) {
  stream << p.first << "," << p.second << " ";
  return stream;
}

template<class T> std::ostream&  operator <<(std::ostream& stream, const vector<T> & v) {
  for (auto el : v)
    stream << el << " ";
  return stream;
}

template<class T> std::ostream&  operator <<(std::ostream& stream, const vector<vector<T>> & v) {
  for (auto line : v) {
    for (auto el : line)
      stream << el << " ";
    stream << "\n";
  }
  return stream;
}

class debugger {
public:
  template<class T> void output (const T& v) {
    cerr << v << " ";
  }
  
  template<class T> debugger& operator , (const T& v) {
    output(v);
    return *this;
  }
} dbg;

////////////////
// templates  //
////////////////

// general
//template size
template<typename T> int size(const T& c) { return int(c.size()); }
//template abs
template<typename T> T abs(T x) { return x < 0 ? -x : x; }
//template sqr
template<typename T> T sqr(T x) { return x*x; }
//template remin
template<typename T> bool remin(T& x, T y) { if (x <= y) return false; x = y; return true; }
//template remax
template<typename T> bool remax(T& x, T y) { if (x >= y) return false; x = y; return true; }
//template factorize
template<class T> inline vector<pair<T,int> > factorize(T n) {vector<pair<T,int> > R;for (T i=2;n>1;){if (n%i==0){int C=0;for (;n%i==0;C++,n/=i);R.push_back(make_pair(i,C));} i++;if (i>n/i) i=n;}if (n>1) R.push_back(make_pair(n,1));return R;}
//template toStr
template<typename T> string toStr(T x) { stringstream ss; ss << x; return ss.str(); }
//helper len
inline int len(const string & x){ return x.length(); }
//helper print_mask
inline void print_mask(int mask, int n){for (int i = 0; i < n; ++i) cerr << (char)('0' + (mask >> i & 1));}
//helper stoi
//int stoi(const string & s){stringstream ss(s); int res; ss >> res; return res;}
//helper itos
string itos(const int & x){stringstream ss; ss << x; return ss.str();}

// types
//template int64
typedef long long            int64 ;
//template uint64
typedef unsigned long long   uint64 ;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef int64 hash_type;

// shortcuts
#define all(_xx)             _xx.begin(), _xx.end()

#define pb                   push_back
#define vl                   vector<long long>
#define vs                   vector<string>
#define vvi                  vector<vector<int>>
#define vvl                  vector<vector<long long>>
#define vd                   vector<double>
#define vc                   vector<char>
#define vvc                  vector<vector<unsigned char>>
#define vpdd                 vector<pair<double,double> >

#define vi                   vector<int>
#define vpii                 vector<pair<int,int>> 
//#define vpii                 vector<pair<short,short> >


#define pii                  pair<int, int>
#define pcc                  pair<char, char>
#define pucc                  pair<uchar, uchar>
#define pll                  pair<long long, long long>
#define pdd                  pair<double, double>
#define mp(XX, YY)           make_pair(XX, YY)
#define fi                   first
#define se                   second

#define ll                   long long
#define ull                  unsigned long long
#define SS                   stringstream

#define ptype unsigned short

// for loops
#define re(II, NN)           for (int II(0), _NN(NN); (II) < (_NN); ++(II))
#define fod(II, XX, YY)      for (int II(XX), _YY(YY); (II) >= (_YY); --(II))
#define fo(II, XX, YY)       for (int II(XX), _YY(YY); (II) <= (_YY); ++(II))
#define foreach(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();++it)

// Useful hardware instructions
#define bitcount             __builtin_popcount
#define gcd                  __gcd

// Useful all around
#define checkbit(n,b)        ((n >> (b)) & 1)
#define pt2(b)               (1LL<<(b))
#define DREP(a)              sort(a.begin(), a.end());a.erase(unique(a.begin(), a.end()),a.end())
#define INDEX(arr,ind)       (lower_bound(arr.begin(), arr.end(),ind)-arr.begin())
#define PAUSE cerr << "Press any key to continue ..."; char xxxx; scanf("%c", &xxxx);

#define v_fill(xx,val) fill(all(xx), val)
#define m_fill(xx,val) memset(xx, val, sizeof(xx))

#define SUM(vv) accumulate(vv.begin(), vv.end(), 0)
#define oo (10001)

#define ALWAYS_INLINE inline __attribute__((always_inline))
#define ALIGNED __attribute__ ((aligned(16)))

#define likely(x)  __builtin_expect(!!(x),1)
#define unlikely(x) __builtin_expect(!!(x),0)

struct Timer {
  steady_clock::time_point ticks;

  const string name;
  bool running;
  int count;
  
  Timer() {;}

  Timer(string _name) : name(_name) {
    count = 0;
    running = false;
  }
  
  double elapsed() {
    auto current = steady_clock::now();
    duration<double> time_span = duration_cast<duration<double>>(current - ticks);
    return time_span.count();
  }

  void startTimer() {
    if (running) return;
    ticks = steady_clock::now();
    running = true;
  }
  
  void checkTimer() {
    double delta = elapsed();
    cerr << name << ": " << delta << " count: " << count;
    if (count) cerr << " mean per sec: " << (1 / delta) * count;
    cerr << endl;
  }
};

mt19937 random_engine;

ALWAYS_INLINE double nextDouble() {return 1.0 * (random_engine() % (1<<30) + 1) / ((1<<30)-1);}
ALWAYS_INLINE int nextInt() {return random_engine();}
ALWAYS_INLINE int nextInt(int range) {return random_engine() % range;}
ALWAYS_INLINE int nextInt(int first, int last) {return random_engine() % (last - first + 1) + first;}

// ----------------------------------------------------------------------------------------------------------------------------------------------- //

//#define LOCAL
//#define DEBUG

#ifdef LOCAL
#define WARN
#define INFO
#define HIGHLIGHT
#define DEBUG
#endif

//#define WARN
//#define HIGHLIGHT

#ifdef DEBUG
#define debug(args...)            {dbg,args; cerr<<"\n"; cerr.flush();}
#else
#define debug(args...)
#endif

#ifdef WARN
#define warn(args...)             {dbg,args; cerr<<endl; cerr.flush();}
#else
#define warn(args...)
#endif

#ifdef INFO
#define info(args...)             {cerr << blue; dbg,args; cerr<< def << "\n"; cerr.flush();}  
#else
#define info(args...)
#endif

#ifdef HIGHLIGHT
#define highlight(args...)        {cerr << red; dbg,args; cerr<< def << "\n"; cerr.flush();}
#else
#define highlight(args...)
#endif

#define CRITICAL_TIME 0.5

#ifdef LOCAL
#define MAX_TIME 3.0
#define TIME_BUFFER 0.1
#else
#define MAX_TIME 3.0
#define TIME_BUFFER 0.1
#endif

struct Scanner {
  char* curPos;
  
  const static int BUF_SIZE = (2000000);
  char input[BUF_SIZE];
  
  FILE * fin;
  
  void init(FILE * _fin) {
    fin = _fin;
    fread(input, 1, sizeof(input), fin);
    curPos = input;
  }
  
  Scanner() {;}
  
  inline void ensureCapacity() {
    int size = input + BUF_SIZE - curPos;
    if (size < 100) {
      memcpy(input, curPos, size);
      fread(input + size, 1, BUF_SIZE - size, fin);
      curPos = input;
    }
  }
  
  inline int nextInt() {
    ensureCapacity();
    while (!isdigit(*curPos) && *curPos != '-')
      ++curPos;
    int res = 0;
    int sign = 1;
    
    if (*curPos == '-')
      sign = -1,
      ++curPos;
    
    while (*curPos >= '0' && *curPos <= '9')
      res = res * 10 + (*(curPos++) & 15);
    return sign * res;
  }
} Sc;

//Timer solution_timer("solution");

#define MAX_N 100111

int N, M, A[MAX_N];

vvi g;

// handles lca and get_route as well
class HeavyPathDecomposition {
public:
  // Color = id of chains
  // Memory : 11 vi (N)
  vi colors, positions;  //Vertex -> Color, Vertex -> Offset
  vi lengths, parents, branches; //Color -> Int, Color -> Color, Color -> Offset
  vi parentnodes, depths;  //Vertex -> Vertex, Vertex -> Int
  vi sortednodes, offsets; //Index -> Vertex, Color -> Index
  vi lefts, rights;  //Vertex -> Index

  int C;

  struct BuildDFSState {
    int n, len, parent;
    BuildDFSState() { }
    BuildDFSState(int n_, int l, int p): n(n_), len(l), parent(p) { }
  };

  void build (const vvi & g, int root) {
    int n = g.size();

    colors.assign(n, -1); positions.assign(n, -1);
    lengths.clear(); parents.clear(); branches.clear();
    parentnodes.assign(n, -1); depths.assign(n, -1);

    sortednodes.clear(); offsets.clear();
    lefts.assign(n, -1); rights.assign(n, -1);

    vi subtreesizes;
    
    // compute subtree sizes
    measure(g, root, subtreesizes);

    typedef BuildDFSState State;

    depths[root] = 0;

    stack<State> st;
    st.push(State(root, 0, -1));
    while (!st.empty()) {
      State t = st.top(); st.pop();

      int n = t.n, len = t.len;
      
      int index = size(sortednodes);
      int color = size(lengths);

      if (t.parent == -3) {
        rights[n] = index;
        continue;
      }

      if(t.parent != -2) {
        assert(size(parents) == color);
        parents.pb(t.parent);
        branches.pb(len);
        offsets.pb(index);
        len = 0;
      }

      colors[n] = color;
      positions[n] = len;

      lefts[n] = index;
      sortednodes.pb(n);

      int max_size = -1, max_v = -1;
      
      for (const auto & v : g[n]) if (colors[v] == -1) {
        if (max_size < subtreesizes[v]) {
          max_size = subtreesizes[v];
          max_v = v;
        }

        parentnodes[v] = n;
        depths[v] = depths[n] + 1;
      }

      st.push(State(n, -1, -3));
      if (max_v == -1) {
        lengths.pb(len + 1);
      } else {
        for (const auto & v : g[n]) if (colors[v] == -1 && v != max_v)
          st.push(State(v, len, color));
        st.push(State(max_v, len + 1, -2));
      }
    }

    C = size(lengths);
  }

  // id of chain and parent vertex of chain
  void get(int v, int &c, int &p) const {
    c = colors[v]; p = positions[v];
  }

  // go up to next chain
  bool go_up(int &c, int &p) const {
    p = branches[c]; c = parents[c];
    return c != -1;
  }

  inline const int *nodesBegin(int c) const { return &sortednodes[0] + offsets[c]; }
  inline const int *nodesEnd(int c) const { return &sortednodes[0] + (c+1 == size(offsets) ? size(sortednodes) : offsets[c+1]); }

  // lca by going up chains at a time until they are on the same chain
  int lowest_common_ancestor(int x, int y) {
    int cx, px, cy, py;

    get(x, cx, px);
    get(y, cy, py);
    
    while(cx != cy) {
      if (depths[*nodesBegin(cx)] < depths[*nodesBegin(cy)])
        go_up(cy, py);
      else
        go_up(cx, px);
    }
    return nodesBegin(cx)[min(px, py)];
  }

  typedef vector<pair<int,pii> > chains;

  void get_route(int u, int v, chains &route) {
    route.clear();
    int w = lowest_common_ancestor(u, v), wc, wp;
    
    get(w, wc, wp);
    
    re (uv, 2) {
      int c, p;
      
      get(uv == 0 ? u : v, c, p);
      int sz = size(route);

      while (1) {
        int top = c == wc ? wp + uv : 0;
        //pii q = uv == 0 ? mp(p + 1, top) : mp(top, p + 1);
        pii q = uv == 0 ? mp(p + 1, top) : mp(top, p + 1);
        if (q.first != q.second) {
          if (uv == 1 && c == wc) {
            //assert(route[sz-1].first == c);
            //assert(route[sz-1].second.first - route[sz-1].second.second == 1);
            //assert(route[sz-1].second.first == q.first);
            route[sz-1].second = mp(route[sz-1].second.second, q.second);
          } else {
            route.push_back(mp(c, q));
          }
        }
        
        if (c == wc) break;
        go_up(c, p);
      }

      if (uv == 1)
        reverse(route.begin() + sz, route.end());
    }
}

private:
  void measure (const vvi &g, int root, vi & out_subtreesizes) const {
    out_subtreesizes.assign(size(g), -1);
    stack<int> st;
    st.push(root);
    while(!st.empty()) {
      auto n = st.top(); st.pop();
      if (out_subtreesizes[n] == -2) {
        int sum = 1;
        for (const auto & v : g[n])
          if (out_subtreesizes[v] != -2)
            sum += out_subtreesizes[v];
        out_subtreesizes[n] = sum;
      } else {
        st.push(n);
        for (const auto & v : g[n])
          if (out_subtreesizes[v] != -2)
            st.push(v);
        out_subtreesizes[n] = -2;
      }
    }
  }
};

struct SegmentTree {
  int N, size;
  vi seg;

  void init (const vi::iterator begin, const vi::iterator end) {
    N = end - begin;
    size = 2 * N;
    while (bitcount(size) != 1) ++size;
    seg.resize(size, -1);

    auto it = begin;
    //warn("segment_trees init");
    fo (n, size / 2, size / 2 + N - 1) {
      seg[n] = *it++;
    }

    fod (n, size / 2 - 1, 1)
      seg[n] = max(seg[2*n], seg[2*n+1]);
  }

  void update (int pos, int val) {
    int n = (size / 2) + pos;
    seg[n] = val;

    for (n >>= 1; n; n >>= 1) 
      seg[n] = max (seg[2*n], seg[2*n+1]);
  }

  int query(int n, int n_l, int n_r, int l, int r) {
    if (r < n_l || l > n_r) return -1;

    if (l <= n_l && n_r <= r) return seg[n];
    int mid = (n_l + n_r) >> 1;

    return max(query(2 * n, n_l, mid, l, r), query(2 * n + 1, mid + 1, n_r, l, r));
  }
} ;

HeavyPathDecomposition hpd;
vector<SegmentTree> segment_trees;

void test_hpd() {
  hpd.build(g, 0);
  warn("# chains:", size(hpd.lengths));

  HeavyPathDecomposition::chains res;

  int max_chains = 0;

  re (steps, 100000) {
    int u = nextInt(N), v = nextInt(N);
    hpd.get_route(u, v, res);

    remax(max_chains, size(res));
  }   

  warn("max # of chains:", max_chains);

  exit(0);
}

int main() {
  random_engine.seed(0);
  //solution_timer.startTimer();

  Sc.init(stdin);
  N = Sc.nextInt(), M = Sc.nextInt();
  re (i, N) A[i] = Sc.nextInt();

  g.resize(N);

  re (i, N - 1) {
    int x = Sc.nextInt(), y = Sc.nextInt();
    --x, --y;
    g[x].pb(y), g[y].pb(x);
  }

  // Heavy Path

  //hpd.build(g, 0);
  
  return 0;

  segment_trees.resize(hpd.C);

  re (c, hpd.C) {
    vi vals (hpd.lengths[c]);
    re (i, size(vals)) vals[i] = A[*(hpd.nodesBegin(c) + i)];
    segment_trees[c].init(all(vals));
  }

  re (i, M) {
    int t = Sc.nextInt(), u = Sc.nextInt(), v = Sc.nextInt();

    if (t == 0) {
      --u;

      int c, pos;
      hpd.get(u, c, pos);
      segment_trees[c].update(pos, v);

      //warn("update:", u, v, "->", c, pos);
      // update val
    } else {
      --u, --v;

      //warn("query:", u, v);

      HeavyPathDecomposition::chains chains;
      hpd.get_route(u, v, chains);

      int result = -1;

      for (const auto & chain : chains) {
        int c = chain.fi, l, r;
        tie (l, r) = chain.se;

        //warn(":", l, r);

        if (l > r) swap(l, r);
        r--;

        auto max_val = segment_trees[c].query(1, 0, segment_trees[c].N - 1, l, r);

        //warn("=>", chain, "l r:", l, r, "answer:", max_val, "interval:", 0, segment_trees[c].N - 1);

        remax (result, max_val);
      }
      // query

      printf("%d\n", result);
    }
  } 

  return 0;
}