Submission #916155

#TimeUsernameProblemLanguageResultExecution timeMemory
916155ThylOneTwo Currencies (JOI23_currencies)C++14
100 / 100
1068 ms69188 KiB
//#################### //TwoCurrencies //#################### #include<bits/stdc++.h> #include <functional> using ll = long long; using namespace std; const int maxiN = 1000042; const int LOG = 19; int n, m, q; namespace PathSum{ vector < int > links[maxiN]; int depth[maxiN]; int up[maxiN][LOG]; void root(int node, int d = 0, int parent = -1) { up[node][0] = parent; depth[node] = d; for (int v: links[node]) if (v != parent) { root(v, d + 1, node); } } int getK(int node, int K) { for (int i = LOG - 1; i >= 0; i--) { if ((K >> i) & 1) { node = up[node][i]; } } return node; } int LCA(int a, int b) { if (depth[b] > depth[a]) swap(a, b); a = getK(a, depth[a] - depth[b]); if (a == b) { return a; } for (int l = LOG - 1; l >= 0; l--) { if (up[a][l] != up[b][l]) { a = up[a][l]; b = up[b][l]; } } return up[a][0]; } pair<int,int> eulerseg[maxiN]; int actEuleur=-1; void computeEuleurTour(int node,int parent = -1){ actEuleur++; eulerseg[node].first = actEuleur; for(int v:links[node])if(parent!=v){ computeEuleurTour(v,node); } actEuleur++; eulerseg[node].second = actEuleur; } template<typename T> struct segtree{ vector<T> vals; int leaf; segtree(int n){ leaf = (1<<((int)ceil(log2(n)))); vals.resize(2*leaf); fill(vals.begin(),vals.end(),0); } segtree()=default; void init(int n){ leaf = (1<<((int)ceil(log2(n)))); vals.resize(2*leaf); fill(vals.begin(),vals.end(),0); } void reset(){ fill(vals.begin(),vals.end(),0); } void _addRange(int a,int b,T val){ if(a==b){ vals[a]+=val; }else if(a&1){ vals[a]+=val; _addRange(a+1,b,val); }else if(b%2==0){ vals[b]+=val; _addRange(a,b-1,val); }else{ _addRange(a/2,b/2,val); } } void addRange(int a,int b,T val){ _addRange(a+leaf,b+leaf,val); } T getVal(int pos){ pos+=leaf; T re = 0; for(int p=pos;p>=1;p>>=1){ re+=vals[p]; } return re; } T sumPath(int a,int b,int lca){ if(b==lca)swap(a,b); if(a==lca){ return getVal(eulerseg[b].first) - getVal(eulerseg[lca].first); }else{ return getVal(eulerseg[a].first)+getVal(eulerseg[b].first) - 2*getVal(eulerseg[lca].first); } } }; void treeStuff(){ root(0, 0, -1); computeEuleurTour(0); //On calcule la tab de LCA for (int l = 1; l < LOG; l++) { for (int i = 0; i < n; i++) { if (up[i][l - 1] == -1) { up[i][l] = -1; } up[i][l] = up[up[i][l - 1]][l - 1]; } } } segtree<ll> pathsum; segtree<int> occurence; template<typename T> void updatePath(segtree<T> &st,int node,int v){ st.addRange(eulerseg[node].first,eulerseg[node].second,v); } }; using namespace PathSum; struct req{ int a,b; ll x,y; int lca; ll totalSum; }; //On stock (cout péage, node) vector<pair<ll,int>> W_child; //les requetes vector<req> queries; //La somme totale de gold enlevé et le nb d'or vector<pair<ll,int>> ans; pair<ll,int> computePath(int a,int b,int lca){ int nbocc=0; ll sumGold=0; nbocc=occurence.sumPath(a,b,lca); sumGold=pathsum.sumPath(a,b,lca); return {sumGold,nbocc}; } const bool AU_MOINS_ASSEZ=true; const bool STRICT_PAS_ASSEZ_ACTIF=false; bool oracle(int r){ return queries[r].y>=(queries[r].totalSum-pathsum.sumPath(queries[r].a,queries[r].b,queries[r].lca)); } void parallel_binary_search(){ /* On dichotomise sur le nombre de piece d'or utilisé */ //initialisation des intervals dichotmique vector<pair<int,int>> requetes(q); for(int i = 0;i<q;i++) requetes[i] = {0,m}; for(int lvl=0;lvl<LOG;lvl++){ //On clean les segtrees pathsum.reset(); occurence.reset(); //On stock la mid val de chaque segments pour les traiter quand on passe sur cette borne vector<int> check[m+1]; for(int i = 0;i<q;i++){ int mid = (requetes[i].first+requetes[i].second)/2; check[mid].push_back(i); } for(int borne=0;borne<=m;borne++){ //On update les segtrees if(borne!=0){ int node = W_child[borne-1].second; ll W = W_child[borne-1].first; updatePath(occurence,node,1); updatePath(pathsum,node,W); } for(int r:check[borne]){ if(requetes[r].first==requetes[r].second){ //calculer les donnes finales ans[r] = computePath(queries[r].a, queries[r].b, queries[r].lca); }else{ bool result = oracle(r); //processus dichotomique if(result==AU_MOINS_ASSEZ){ requetes[r] = {requetes[r].first,borne}; }else{ requetes[r] = {borne+1,requetes[r].second}; } } } } } } signed main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m >> q; queries.resize(q); occurence.init(2*n); pathsum.init(2*n); ans.resize(q); fill(depth, depth + maxiN, -1); for(int i = 0;i<q;i++)ans[i] = {-1,-1}; vector < pair < int, int >> edges; for (int i = 0; i < n - 1; i++) { int a, b; cin >> a >> b; a--; b--; edges.push_back({a,b}); links[a].push_back(b); links[b].push_back(a); } treeStuff(); for (int i = 0; i < m; i++) { int p, c; cin >> p >> c; p--; auto a = edges[p].first; auto b = edges[p].second; if (depth[a] < depth[b]) swap(a, b); updatePath(occurence,a,1); updatePath(pathsum,a,c); W_child.push_back({c,a}); } sort(W_child.rbegin(),W_child.rend()); for (int i = 0; i < q; i++) { int a,b; ll x, y; cin >> a >> b >> x >> y; a--; b--; int lca = LCA(a, b); queries[i] = {a,b,x,y,lca,pathsum.sumPath(a,b,lca)}; } //usagé donc on nettoie pathsum.reset(); occurence.reset(); parallel_binary_search(); for(int i = 0;i<q;i++){ ll tot = queries[i].totalSum-ans[i].first; if(queries[i].x>=ans[i].second && queries[i].y>=tot) cout<<queries[i].x-ans[i].second<<'\n'; else cout<<-1<<'\n'; } return 0; };
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...