제출 #239565

#제출 시각아이디문제언어결과실행 시간메모리
239565jtnydv25Construction of Highway (JOI18_construction)C++17
100 / 100
1266 ms66148 KiB
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define sd(x) scanf("%d", &(x))
#define pii pair<int, int>
#define F first
#define S second
#define all(c) ((c).begin()), ((c).end())
#define sz(x) ((int)(x).size())
#define ld long double

template<class T,class U>
ostream& operator<<(ostream& os,const pair<T,U>& p){
	os<<"("<<p.first<<", "<<p.second<<")";
	return os;
}

template<class T>
ostream& operator <<(ostream& os,const vector<T>& v){
	os<<"{";
	for(int i = 0;i < (int)v.size(); i++){
		if(i)os<<", ";
		os<<v[i];
	}
	os<<"}";
	return os;
}

#ifdef LOCAL
#define cerr cout
#else
#endif

#define TRACE

#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
	cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
	const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif

// 0-indexed
// O(n) precomputation, O(1) query lca
// O(n logn) precomputation, O(1) query kth ancestor
struct tree {
	int n, block_size, num_blocks;
	vector<vector<int>> adj, val;
	vector<int> num, floorlog;
	tree(){}
	tree(int n) : n(n), adj(n){ }
	void add_edge(int s, int t) {
		adj[s].push_back(t);
		adj[t].push_back(s);
	}
	vector<int> pos, tour, depth, pos_end;
	vector<vector<int>> table;
	int argmin(int i, int j) { return depth[i] < depth[j] ? i : j; }
	// O(n) preprocessing, O(1) lca query
	void rootify(int r) {
		pos.resize(n);
		pos_end.resize(n);
		// euler tour
		function<void (int,int,int)> dfs = [&](int u, int p, int d) {
			pos[u] = pos_end[u] = depth.size();
			tour.push_back(u);
			depth.push_back(d);
			for (int v: adj[u]) {
				if (v != p) {
					dfs(v, u, d+1);
					pos_end[u] = (int)depth.size();
					tour.push_back(u);
					depth.push_back(d);
				}
			}
		}; 

		dfs(r, r, 0);

		floorlog.resize(tour.size() + 1);

		for(int i = 0; (1 << i) <= tour.size(); i++)
			for(int j = (1 << i); j < (1 << (i + 1)) && j <= tour.size(); j++)
				floorlog[j] = i;

		int logn = floorlog[tour.size()];
		block_size = logn / 2 + 1;
		num_blocks = ((int)tour.size() - 1) / block_size + 1;
		table.resize(logn+1, vector<int>(num_blocks));
		num.resize(num_blocks);
		val.resize(block_size + 1, vector<int>(1 << block_size));

		for(int i = 0; i < tour.size(); i += block_size){
			int mn = i;
			int v = 0;
			int block = i / block_size;
			int j = i;
			for(; j < tour.size() && j < i + block_size; j++){
				mn = argmin(mn, j);
				if(j != i){
					v = 2 * v + (depth[j] == depth[j - 1] + 1);
				}
			}
			table[0][block] = mn;
			num[block] = v << (block_size - j + i);
		}

		for (int h = 1; (1 << h) <= num_blocks; ++h) 
			for (int i = 0; i + (1<<h) <= num_blocks; ++i)
				table[h][i] = argmin(table[h - 1][i], table[h - 1][i+(1<<(h - 1))]);

		for(int i = 0; i < (1 << block_size); i++){
			int prefix = 0, mn = 0, curr = 0;
			for(int j = 0; j < block_size; j++){
				prefix += 2 * (i >> (block_size - 1 - j) & 1) - 1;
				if(mn > prefix){
					mn = prefix;
					curr = j + 1;
				}
				val[j + 1][i >> (block_size - 1 - j)] = curr;
			}
		}
	}

	inline int same_block_lca(int block, int i, int j){
		if(i == j) return i + block * block_size;
		int l = j - i;
		int mask = (num[block] >> (block_size - j - 1)) & ((1 << l) - 1);
		return block * block_size + i + val[l][mask];
	}

	int lca(int a, int b){
		a = pos[a]; b = pos[b];
		if(a > b) swap(a, b);
		int block_a = a / block_size;
		int block_b = b / block_size;
		int ind_a = a - block_a * block_size;
		int ind_b = b - block_b * block_size;
		if(block_a == block_b) return tour[same_block_lca(block_a, ind_a, ind_b)];
		int ans = argmin(same_block_lca(block_a, ind_a, block_size - 1), same_block_lca(block_b, 0, ind_b));
		if(block_b > block_a + 1){
			int h = floorlog[block_b - block_a - 1];
			int t = argmin(table[h][block_a + 1], table[h][block_b- (1<<h)]);
			ans = argmin(ans, t);
		}
		return tour[ans];
	}

	inline int dist(int i, int j){
		return depth[pos[i]] + depth[pos[j]] - 2 * depth[pos[lca(i, j)]];
	}

	inline int getDepth(int u){
		return depth[pos[u]];
	}

	inline bool isAncestor(int a, int b){
		return pos[b] >= pos[a] && pos[b] <= pos_end[a];
	}

	inline bool isOn(int c, int a, int b){
		return isAncestor(lca(a, b), c) && (isAncestor(c, a) || isAncestor(c, b));
	}
	inline bool pathsIntersect(int a, int b, int c, int d){
		int lab = lca(a, b), lcd = lca(c, d);
		return isOn(lab, c, d) || isOn(lcd, a, b);
	}
    vector<vector<int>> chains, par;
    vector<int> sizes, st, en, chain_index, maxDepth;

	void straighten(int r){
		const int logN = 20;
		st.resize(n);
		en.resize(n);
		sizes.resize(n);
		maxDepth.resize(n);
		par.assign(logN, vector<int>(n, 0));
		int timer = 0;
		function<void(int, int, int)> dfs = [&](int s, int p, int d){
			par[0][s] = p;
			st[s] = ++timer;
			maxDepth[s] = d;
			for(int v : adj[s]) if(v != p){
				dfs(v, s, d + 1);
				maxDepth[s] = max(maxDepth[s], maxDepth[v]);
			}
			en[s] = timer;
			sizes[s] = en[s] - st[s] + 1;
		};
		dfs(r, r, 0);
		for(int i = 1; i < logN; i++)
			for(int j = 0; j < n; j++) par[i][j] = par[i - 1][par[i - 1][j]];
	}
    // for kth ancestor in O(1)
    void hld(int r){
		straighten(r);
        function<void(int, int, vector<int> &)> dfs = [&](int s, int p, vector<int> & chain){
			int bigc = -1;
			for(int v : adj[s]) if(v != p){
				if(bigc == -1 || maxDepth[v] > maxDepth[bigc]) bigc = v;
			}
			for(int v : adj[s]) if(v != p){
				if(v == bigc){
					chain.push_back(v);
					dfs(v, s, chain);
				} else{
					vector<int> new_chain = {v};
					dfs(v, s, new_chain);
				}
			}
			if(bigc == -1) chains.push_back(chain);
        };
		vector<int> init_chain = {r};
		dfs(r, r, init_chain);
		chain_index.resize(n);
		int ind = 0;
		for(auto & it : chains){
			reverse(all(it));
			int l = sz(it);
			int v = it.back();
			it.resize(2 * l);
			for(int i = 0; i < l; i++){
				chain_index[it[i]] = ind;
				v = par[0][v];
				it[l + i] = v;
			}
			ind++;
		}
    }
	inline int msb(int x){
		return 31 - __builtin_clz(x);
	}
	int kthAncestor(int x, int k){
		if(k==0) return x;
		int w = msb(k);
		int v = par[w][x];
		k -= (1 << w);
		int ind = chain_index[v];
		int pos = getDepth(chains[ind][0]) - getDepth(v);
		return chains[ind][pos + k];
	}
	void input(){
        for(int i = 1; i < n - 1; i++){
            int x, y;
            scanf("%d %d", &x, &y);
            add_edge(x, y);
        }
    }
};

const int N = 100005;
const int logN = 20;

int arrival[N], par[logN][N], depth[N], A[N], B[N], C[N];
int st[N], en[N], timer;

vector<int> children[N];
void dfs(int s, int d){
	depth[s] = d;
	st[s] = timer++;
	for(int v : children[s]) dfs(v, d + 1);
	en[s] = timer - 1;
}

// 0-indexed
template<class T>
struct segtree{
	int n;
	vector<T> t;
	T def;
	inline T combine(T a, T b){
		return arrival[a] > arrival[b] ? a : b;
	}

	segtree(vector<T> & inp, T def = T()) : n(sz(inp)), def(def){
		t.resize(2 * n, def);
		for(int i = 0; i < n; i++) t[n + i] = inp[i];
		for(int i = n - 1; i > 0; --i) t[i] = combine(t[i<<1], t[i<<1|1]);
	}

	void modify(int p, T value) { // modify a[p] = value
		// value = combine(value, t[p + n]); // if a[p] = combine(a[p], value)
		for (t[p += n] = value; p >>= 1; ) t[p] = combine(t[p<<1], t[p<<1|1]);
	}

	T query(int l, int r) {  // compute on interval [l, r]
    r++;
		T resl = def, resr = def;
		for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
			if (l&1) resl = combine(resl, t[l++]);
			if (r&1) resr = combine(t[--r], resr);
		}
		return combine(resl, resr);
	}
};

ll bit[N];
void add(int x, int y){
	x++;
	for(; x < N; x += x & -x) bit[x] += y;
}

ll get(int x){
	x++;
	ll ret = 0;
	for(; x; x -= x & -x) ret += bit[x];
	return ret;
}

ll get(int l, int r){
	return get(r) - get(l - 1);
}

int getKth(int x, int k){
	for(int i = 0; i < logN; i++) if(k >> i & 1) x = par[i][x];
	return x;
}

int main(){
	int n; sd(n);
	vector<int> V(n);
	segtree<int> stree(V);
	map<int, int> compress; set<int> vals;
	tree T(n);
	for(int i = 0; i < n; i++){
		sd(C[i]);
		vals.insert(C[i]);
	}

	int pos = 0;
	for(int v : vals) compress[v] = pos++;

	for(int i = 0; i < n; i++) C[i] = compress[C[i]];

	for(int i = 1; i < n; i++){
		sd(A[i]); sd(B[i]);
		A[i]--; B[i]--;
		T.add_edge(A[i], B[i]);
		arrival[B[i]] = i;
		par[0][B[i]] = A[i];
		children[A[i]].push_back(B[i]);
	}
	dfs(0, 0);
	T.rootify(0);
	T.hld(0);

	for(int j = 1; j < logN; j++) for(int i = 0; i < n; i++) par[j][i] = par[j - 1][par[j - 1][i]];

	for(int i = 1; i < n; i++){
		int x = B[i];
		int curr = 1;
		vector<pii> vec;
		ll num = 0;
		while(curr <= depth[x]){
			int y = T.kthAncestor(x, curr);
			// int y = getKth(x, curr);
			int latestNode = stree.query(st[y], en[y]); // last added in x's subtree
			// maximum with the same value
			int lo = curr, hi = depth[x];
			while(lo < hi){
				int mid = (lo + hi + 1) >> 1;
				int node = T.kthAncestor(x, mid);
				if(stree.query(st[node], en[node]) == latestNode) lo = mid;
				else hi = mid - 1;
			}
			int v = C[latestNode], cnt = lo - curr + 1;

			vec.push_back({v, cnt}); // v comes cnt times

			num += cnt * (ll) get(0, v - 1); // the values below should be smaller than this

			add(v, cnt);
			curr = lo + 1;
		}
		for(auto it : vec) add(it.F, -it.S); // reinitialize bit to 0
		printf("%lld\n", num);
		
		stree.modify(st[x], x);
	}
}

컴파일 시 표준 에러 (stderr) 메시지

construction.cpp: In member function 'void tree::rootify(int)':
construction.cpp:90:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   for(int i = 0; (1 << i) <= tour.size(); i++)
                  ~~~~~~~~~^~~~~~~~~~~~~~
construction.cpp:91:50: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    for(int j = (1 << i); j < (1 << (i + 1)) && j <= tour.size(); j++)
                                                ~~^~~~~~~~~~~~~~
construction.cpp:101:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   for(int i = 0; i < tour.size(); i += block_size){
                  ~~^~~~~~~~~~~~~
construction.cpp:106:12: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    for(; j < tour.size() && j < i + block_size; j++){
          ~~^~~~~~~~~~~~~
construction.cpp: In function 'int main()':
construction.cpp:5:20: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
 #define sd(x) scanf("%d", &(x))
               ~~~~~^~~~~~~~~~~~
construction.cpp:328:9: note: in expansion of macro 'sd'
  int n; sd(n);
         ^~
construction.cpp:5:20: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
 #define sd(x) scanf("%d", &(x))
               ~~~~~^~~~~~~~~~~~
construction.cpp:334:3: note: in expansion of macro 'sd'
   sd(C[i]);
   ^~
construction.cpp:5:20: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
 #define sd(x) scanf("%d", &(x))
               ~~~~~^~~~~~~~~~~~
construction.cpp:344:3: note: in expansion of macro 'sd'
   sd(A[i]); sd(B[i]);
   ^~
construction.cpp:5:20: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
 #define sd(x) scanf("%d", &(x))
               ~~~~~^~~~~~~~~~~~
construction.cpp:344:13: note: in expansion of macro 'sd'
   sd(A[i]); sd(B[i]);
             ^~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...