이 제출은 이전 버전의 oj.uz에서 채점하였습니다. 현재는 제출 당시와는 다른 서버에서 채점을 하기 때문에, 다시 제출하면 결과가 달라질 수도 있습니다.
//####################
//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;
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;
}
};
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);
}
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){
ll nbocc=0;
ll sumGold=0;
if(a==lca && b==lca){
nbocc=0;
}else if(a==lca){
nbocc=occurence.getVal(eulerseg[b].first)-occurence.getVal(eulerseg[a].first);
sumGold=pathsum.getVal(eulerseg[b].first)- pathsum.getVal(eulerseg[a].first);
}else if(b==lca){
nbocc=occurence.getVal(eulerseg[a].first)-occurence.getVal(eulerseg[b].first);
sumGold=pathsum.getVal(eulerseg[a].first)- pathsum.getVal(eulerseg[b].first);
}else{
nbocc=occurence.getVal(eulerseg[b].first)+occurence.getVal(eulerseg[a].first)-2*occurence.getVal(eulerseg[lca].first);;
sumGold=pathsum.getVal(eulerseg[b].first)+ pathsum.getVal(eulerseg[a].first)- 2*pathsum.getVal(eulerseg[lca].first);;
}
return {sumGold,nbocc};
}
const bool AU_MOINS_ASSEZ=true;
const bool STRICT_PAS_ASSEZ_ACTIF=false;
bool oracle(int r){
pair<ll,int> rep = computePath(queries[r].a,queries[r].b,queries[r].lca);
return queries[r].y>=(queries[r].totalSum-rep.first);
}
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,computePath(a,b,lca).first};
}
//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 time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |