1878G - wxhtzdy ORO Tree - CodeForces Solution


binary search data structures dfs and similar divide and conquer trees

Please click on ads to support us..

C++ Code:

#include <bits/stdc++.h>
using namespace std;

const int B = 3;

struct node {
  int a[2 * B];
  int len;

  node() {
    for (int i = 0; i < B; i++) {
      a[i] = 1e9;
      a[B + i] = -1e9;
    }
    len = 1;
  }

  node(const node & t) {
    for (int i = 0; i < B; i++) {
      a[i] = t.a[i];
      a[B + i] = t.a[B + i];
    }
    len = t.len;
  }

  node(int x) {
    for (int i = 0; i < B; i++) {
      a[i] = 1e9;
      a[B + i] = -1e9;
      if ((x >> i) & 1) {
        a[i] = 0;
        a[B + i] = 0;
      }
    }
    this->len = 1;
  }

	// NOT COMMUTATIVE
	node operator+(node const & b) {
    node ret = node();
    ret.len = len + b.len;
    for (int i = 0; i < B; i++) {
      ret.a[i] = min(b.a[i] + len, a[i]);
      ret.a[B + i] = max(len + b.a[B + i], this->a[B + i]);
    }
		return ret;
	}

	node reverse() {
		node ret = node();
    ret.len = len;
    for (int i = 0; i < B; i++) {
      if (a[B + i] > -1e8) {
        ret.a[i] = len - a[B + i] - 1;
      } else {
        ret.a[i] = 1e9;
      }
      if (a[i] < 1e8) {
        ret.a[B + i] = len - a[i] - 1;
      } else {
        ret.a[B + i] = -1e9;
      }
    }
		return ret;
	}
};


template<class T>
struct LCA {
	T ID;
	bool online = false;
	const int LEVELS = 18;
	vector<vector<int > > v;
	vector<int> depth;
	vector<T> a;
	vector<vector<pair<int, T> > > jump;
	vector<pair<int, int> > euler_tour;

	void getDepth(int x, int last) {
		if (last != -1) depth[x] = depth[last] + 1;
		for (int n : v[x]) {
			if (last == n) continue;
			getDepth(n, x);
		}
	}
	
	explicit LCA(vector<vector<int> > & _v, vector<T> & _a, T _ID = T()) : ID(_ID) {
		v = _v;
		a = _a;

		int n = v.size();
		depth.assign(n, 0);
		jump.resize(LEVELS);

		for (int i = 0; i < LEVELS; i++) {
			jump[i].assign(n, {-1, ID});
		}
		euler_tour.resize(n);
		getDepth(0, -1);

		int cnt = 0;
		// populate jump[i] with the 2^0th ancestor of i, and d with the euler

		function<void (int x, int & cnt, int last)> lca_dfs = [&](int x, int & cnt, int last) {
			jump[0][x] = {last, a[x]};
			int s = cnt;
			for (auto u : v[x]) {
				if (u == last) continue;
				lca_dfs(u, ++cnt, x);
			}
			int e = cnt;
			euler_tour[x] = {s, e};
		};

		lca_dfs(0, cnt, -1);

		update_jump();
	}
  void update_jump() {
    for (int i = 1; i < jump.size(); i++) {
			for (int j = 0; j < jump[i].size(); j++) {
				auto old = jump[i - 1][j];
				if (old.first == -1) continue;
				auto next = jump[i - 1][old.first];
				jump[i][j] = {next.first, old.second + next.second};
			}
		}
  }

	void addEdge(int x, int y, T w) {
		online = true;
		if (y >= a.size()) {
			assert(y == a.size());
			a.push_back(w);
			v.push_back({x});
			depth.push_back(depth[x] + 1);
			for (int i = 0; i < jump.size(); i++) {
				jump[i].push_back({});
			}
		}
		a[y] = w;
		v[y] = {x};
		depth[y] = depth[x] + 1;
		v[x].push_back(y);
		jump[0][y] = {x, w};
		for (int i = 1; i < jump.size(); i++) {
			auto old = jump[i - 1][y];
			if (old.first == -1) continue;
			auto next = jump[i - 1][old.first];
			jump[i][y] = {next.first, old.second + next.second};
		}
	}

	// return if a is an ancestor of b. This runs in log(n)
	bool isAncestorOnline(int a, int b) {
		if (depth[b] < depth[a]) return false;
		return jmp(b, depth[b] - depth[a]).first == a;
	}

	// runs in constant time
	bool isAncestorOffline(int a, int b) {
		return (euler_tour[a].first <= euler_tour[b].first && euler_tour[a].second >= euler_tour[b].second);
	}

	// THIS IS LOG^2(n) if edges are added online and LOG(n) otherwise.
	T query(int x, int y) {
		int anc = lca(x, y);
		auto xa = jmp(x, depth[x] - depth[anc]).second + a[anc];
		auto xb = jmp(y, depth[y] - depth[anc]).second.reverse();
		return xa + xb;
	}

	bool isAncestor(int a, int b) {
		if (online) {
			return isAncestorOnline(a, b);
		}
		return isAncestorOffline(a, b);
	}

	// jumps to the dth ancestor of x
	// returns the ancestor with the answer on a segment (NOT INCLUDING LAST NODE)
	pair<int, T> jmp(int x, int d) {
		pair<int, T> ret = {x, ID};
		for (int i = 0; i < LEVELS; i++) {
			if ((1 << i) & d) {
				ret = {jump[i][x].first, ret.second + jump[i][x].second};
				x = ret.first;
			}
			if (x == -1) return {-1, ID};
		}
		return ret;
	}

	int lca(int a, int b) {
		int low = 0;
		int high = 1 << LEVELS;
		int best = -1;
    
		while (low <= high) {
			int mid = (low + high) / 2;
			auto anc = jmp(a, mid);
			if (anc.first == -1) {
				high = mid - 1;
				continue;
			}
			if (isAncestor(anc.first, b)) {
				high = mid - 1;
				best = anc.first;
			} else {
				low = mid + 1;
			}
		}
		return best;
	}
};

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int tests;
  cin >> tests;
  for (int test = 1; test <= tests; test++) {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i< n; i++) cin >> a[i];
    vector<vector<int> > v(n);
    for (int i = 0; i < n - 1; i++) {
      int x, y;
      cin >> x >> y;
      x--;
      y--;
      v[x].push_back(y);
      v[y].push_back(x);
    }
    int qq;
    cin >> qq;
    vector<pair<int, int> > q(qq);
    for (auto & x : q) {
      cin >> x.first >> x.second;
      x.first--;
      x.second--;
    }
    vector<vector<array<int, 2> > > sw(qq);
    vector<node> nd(n);
    LCA lca(v, nd);
    for (int m = 0; m < 32 / B; m++) {
      long long MSK = ((1LL << B) - 1) << (m * B);
      for (int i = 0; i < n; i++) {
        nd[i] = node(((1LL * a[i]) & MSK) >> (m * B));
        lca.jump[0][i].second = nd[i];
      }
      lca.a = nd;
      lca.update_jump();
      for (int j = 0; j < qq; j++) {
        auto ret = lca.query(q[j].first, q[j].second);
        vector<array<int, 2> > v;
        int cnt = 0;
        for (int i = 0; i < B; i++) {
          if (ret.a[i] != 1e9) {
            sw[j].push_back({ret.a[i], 1});
            sw[j].push_back({ret.a[B + i] + 1, -1});
          }
        }
      }
    }
    for (int i = 0; i < qq; i++) {
      sort(sw[i].begin(), sw[i].end());
      int cur = 0;
      int cnt = sw[i].size() / 2;
      int maxi = sw[i].size() / 2;
      for (int j = 0; j < sw[i].size(); j++) {
        cur += sw[i][j][1];
        maxi = max(maxi, cnt + cur);
      }
      cout << maxi << " \n"[i == qq - 1];
    }
  }

  // IF STUCK:
    // DIV CONQUER?
    // CONSIDER SMALL CASES
    // INDUCTION
  return 0;
}


Comments

Submit
0 Comments
More Questions

281A - Word Capitalization
1646A - Square Counting
266A - Stones on the Table
61A - Ultra-Fast Mathematician
148A - Insomnia cure
1650A - Deletions of Two Adjacent Letters
1512A - Spy Detected
282A - Bit++
69A - Young Physicist
1651A - Playoff
734A - Anton and Danik
1300B - Assigning to Classes
1647A - Madoka and Math Dad
710A - King Moves
1131A - Sea Battle
118A - String Task
236A - Boy or Girl
271A - Beautiful Year
520B - Two Buttons
231A - Team
479C - Exams
1030A - In Search of an Easy Problem
158A - Next Round
71A - Way Too Long Words
160A - Twins
1A - Theatre Square
1614B - Divan and a New Project
791A - Bear and Big Brother
1452A - Robot Program
344A - Magnets