Submission #781999

#TimeUsernameProblemLanguageResultExecution timeMemory
781999ArturgoTourism (JOI23_tourism)C++14
100 / 100
297 ms40748 KiB
#include <bits/stdc++.h>
using namespace std;

const int INIT = (1 << 17) - 1;

int sommes[(1 << 18)];

void ajoute(int pos, int val) {
	pos += (1 << 17);
	while(pos != 0) {
		sommes[pos] += val;
		pos /= 2;
	}
}

int somme_entre(int deb, int fin) {
	deb += (1 << 17);
	fin += (1 << 17);
	
	int somme = 0;
	while(deb < fin) {
		if(deb % 2 == 1) {
			somme += sommes[deb];
			deb++;
		}
		if(fin % 2 == 1) {
			fin--;
			somme += sommes[fin];
		}
		deb /= 2;
		fin /= 2;
	}
	
	return somme;
}

struct Req {
	int deb, fin, id;
};

struct Inter {
	int deb, fin, couleur;
};

int N, M, Q;

vector<int> voisins[100 * 1000];
vector<int> positions;
vector<Req> reqs[100 * 1000];
int reponses[100 * 1000];
int profs[100 * 1000];

int posPeigne;
int gauches[100 * 1000];
int droites[100 * 1000];

int remontes[20][100 * 1000];

int id_chaine[100 * 1000];
vector<vector<Inter>> chaines;

bool est_parent(int u, int v) {
	return gauches[u] <= gauches[v] && droites[v] <= droites[u];
}

bool est_parent_strict(int u, int v) {
	if(u == -1) return true;
	return gauches[u] < gauches[v] && droites[v] < droites[u];
}

pair<int, int> up(pair<int, int> a, pair<int, int> b) {
	int l, r;
	
	if(gauches[a.first] < gauches[b.first])
		l = a.first;
	else
		l = b.first;
	
	if(gauches[a.second] < gauches[b.second])
		r = b.second;
	else
		r = a.second;
	
	return {l, r};
}

pair<int, int> arbre_dfs[(1 << 18)];

pair<int, int> get_bords(int deb, int fin) {
	pair<int, int> sol = {positions[deb], positions[deb]};

	deb += (1 << 17);
	fin += (1 << 17);	
	
	while(deb < fin) {
		if(deb % 2 == 1) {
			sol = up(sol, arbre_dfs[deb]);
			deb++;
		}
		if(fin % 2 == 1) {
			fin--;
			sol = up(sol, arbre_dfs[fin]);
		}
		deb /= 2;
		fin /= 2;
	}
	
	return sol;
}

int build_ds(int u, int p = -1, int prof = 0) {
	remontes[0][u] = p;
	profs[u] = prof;
	gauches[u] = posPeigne++;
	
	int taille = 1;
	pair<int, int> mel_fils = {-1, -1};
	
	for(int v : voisins[u]) {
		if(v == p) continue;
		int ret = build_ds(v, u, prof + 1);
		taille += ret;
		
		mel_fils = max(mel_fils, {ret, id_chaine[v]});
	}
	
	if(mel_fils.first == -1) {
		id_chaine[u] = chaines.size();
		chaines.push_back({});
		chaines.back().push_back({p, u, INIT});
	}
	else {
		id_chaine[u] = mel_fils.second;
		chaines[mel_fils.second].push_back({p, u, INIT});
	}
	
	droites[u] = posPeigne++;
	return taille;
}

int lca(int u, int v) {
	if(est_parent(u, v)) return u;

	for(int rem = 19;rem >= 0;rem--) {
		int w = remontes[rem][u];
		if(w != -1 && !est_parent(w, v)) {
			u = w;
		}
	}
	
	return remontes[0][u];
}

int get_prof(int u) {
	if(u == -1) return -1;
	return profs[u];
}

void recolorie(int u, int color) {
	while(u != -1) {
		vector<Inter>& chaine = chaines[id_chaine[u]];
		
		int start = chaine.back().deb;
		int end;
		int last_col;
		
		while(!chaine.empty()
		 && est_parent_strict(chaine.back().deb, u)) {
			end = chaine.back().fin;
			last_col = chaine.back().couleur;
			
			int sz = get_prof(chaine.back().fin)
			- get_prof(chaine.back().deb);
			int col = chaine.back().couleur;
			ajoute(col, -sz);
			
			chaine.pop_back();
		}
		
		if(u != end) {
			chaine.push_back({u, end, last_col});
			ajoute(last_col, 
				get_prof(end)
				- get_prof(u)
			);
		}
		
		chaine.push_back({start, u, color});
		ajoute(color, 
			get_prof(u)
			- get_prof(start)
		);
		
		u = start;
	}
}

void solve() {
	build_ds(0);
	
	for(int prof = 1;prof < 20;prof++) {
		for(int i = 0;i < N;i++) {
			if(remontes[prof - 1][i] == -1)
				remontes[prof][i] = -1;
			else
				remontes[prof][i] = remontes[prof - 1][
					remontes[prof - 1][i]
				];
		}
	}
	
	for(int i = 0;i < M;i++) {
		arbre_dfs[(1 << 17) + i] = {positions[i], positions[i]};
	}
	
	for(int i = (1 << 17) - 1;i > 0;i--) {
		arbre_dfs[i] = up(arbre_dfs[2 * i], arbre_dfs[2 * i + 1]);
	}
	
	for(int l = M - 1;l >= 0;l--) {
		recolorie(positions[l], l);
		
		for(Req r : reqs[l]) {
			int res = somme_entre(l, r.fin);
			
			pair<int, int> bords = get_bords(l, r.fin);
			
			res -= profs[lca(
				bords.first, bords.second
			)];
			
			reponses[r.id] = res;
		}
	}
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	cin >> N >> M >> Q;
	
	for(int i = 0;i < N - 1;i++) {
		int deb, fin;
		cin >> deb >> fin;
		deb--; fin--;
		voisins[deb].push_back(fin);
		voisins[fin].push_back(deb);
	}
	
	for(int i = 0;i < M;i++) {
		int pos;
		cin >> pos;
		pos--;
		positions.push_back(pos);
	}
	
	for(int i = 0;i < Q;i++) {
		int deb, fin;
		cin >> deb >> fin;
		deb--;
		reqs[deb].push_back({deb, fin, i});
	}
	
	solve();
	
	for(int i = 0;i < Q;i++) {
		cout << reponses[i] << endl;
	}
	return 0;
}

Compilation message (stderr)

tourism.cpp: In function 'void recolorie(int, int)':
tourism.cpp:9:6: warning: 'last_col' may be used uninitialized in this function [-Wmaybe-uninitialized]
    9 |  pos += (1 << 17);
      |  ~~~~^~~~~~~~~~~~
tourism.cpp:165:7: note: 'last_col' was declared here
  165 |   int last_col;
      |       ^~~~~~~~
tourism.cpp:156:16: warning: 'end' may be used uninitialized in this function [-Wmaybe-uninitialized]
  156 |  return profs[u];
      |                ^
tourism.cpp:164:7: note: 'end' was declared here
  164 |   int end;
      |       ^~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...