Submission #862077

#TimeUsernameProblemLanguageResultExecution timeMemory
862077LibClosing Time (IOI23_closing)C++17
100 / 100
171 ms50872 KiB
#include "closing.h" #include <bits/stdc++.h> using namespace std; //self explanatory enough int Type[200003]; int Check[200003]; int BFSCheck[200003]; long long Cost1[200003]; long long Cost2[200003]; long long DistX[200003]; long long DistY[200003]; vector <int> XYPath; int check[200003]; int check2[300003]; long long N,X,Y,K,n,ans1,ans2; struct edge{ int first; long long second; }; vector <edge> VTemp; vector <vector <edge> > adj; priority_queue <pair <long long,int> > pq1,pq2,pq3,pq4; int max_score(int N, int X, int Y, long long K, std::vector<int> U, std::vector<int> V, std::vector<int> W) { //just a bunch of initializing int n=N; int x=X; int y=Y; long long k=K; int q,s,e; long long tans,Budget,len; vector <int> CList; int cur,cur2; int t; long long t2; pair <long long,int> tpos; while(!pq1.empty()){ pq1.pop(); } while(!pq2.empty()){ pq2.pop(); } while(!pq3.empty()){ pq3.pop(); } while(!pq4.empty()){ pq4.pop(); } XYPath.clear(); adj.clear(); n=N; for(int i=0;i<=n+1;i++){ adj.push_back(VTemp); check[i]=0; Cost1[i]=0; Cost2[i]=0; DistX[i]=0; DistY[i]=0; Type[i]=0; } ans1=0; ans2=0; //generating the tree for(int i=1;i<n;i++){ s=U[i-1]; e=V[i-1]; len=W[i-1]; adj[s].push_back({e,len}); adj[e].push_back({s,len}); } //dumbass can't even DFS properly, proceeds to BFS twice for ~70 lines CList.clear(); cur=0; cur2=0; for(int i=0;i<=n+1;i++){ BFSCheck[i]=0; } CList.push_back(X); BFSCheck[X]=1; DistX[X]=0; while(cur<CList.size()){ t=CList[cur]; for(int i=0;i<adj[t].size();i++){ if(BFSCheck[adj[t][i].first]==0){ BFSCheck[adj[t][i].first]=1; DistX[adj[t][i].first]=DistX[t]+adj[t][i].second; CList.push_back(adj[t][i].first); } } cur++; } CList.clear(); cur=0; cur2=0; for(int i=0;i<=n+1;i++){ BFSCheck[i]=0; } CList.push_back(Y); BFSCheck[Y]=1; DistY[Y]=0; while(cur<CList.size()){ t=CList[cur]; for(int i=0;i<adj[t].size();i++){ if(BFSCheck[adj[t][i].first]==0){ BFSCheck[adj[t][i].first]=1; DistY[adj[t][i].first]=DistY[t]+adj[t][i].second; CList.push_back(adj[t][i].first); } } cur++; } /*calculating the cost to "upgrade"vertex i from lv0 => lv1 and lv1 => lv2, which corresponds to Cost1[i] and Cost2[i] respectively also determining the "type" of each vertex i as well: - type 0: vertices with Cost1[i] <= Cost2[i] and does NOT lie on the XY - path - Type 1: vertices with Cost1[i] > Cost2[i] - Type 2: Vertices that lies on the XY - path */ for(int i=0;i<n;i++){ Cost1[i]=min(DistX[i],DistY[i]); Cost2[i]=max(DistX[i],DistY[i])-Cost1[i]; if(Cost1[i]*2+Cost2[i]==DistX[Y]){ XYPath.push_back(i); } if(Cost2[i]<=Cost1[i]){ Type[i]=1; } } //First case: The max level for all vertices is 1. Just grab the cheapest Lv1s and call it a day for(int i=0;i<XYPath.size();i++){ Type[XYPath[i]]=2; } //pq4 is the priority queue that is used for this case. Doesn't really matter otherwise. //ans1 is the max sum of "levels" for this case //also, I push -Cost1[i] (and later on -Cost2[i] as well) into the priority queue because I don't want to make custom sort functions. Makes things much messier. -max heap is min heap //anyways for(int i=0;i<n;i++){ pq4.push({-Cost1[i],i}); } Budget=K; while(Budget>0&&!pq4.empty()){ Budget+=pq4.top().first; check2[pq4.top().second]=1; if(Budget>=0){ ans1++; pq4.pop(); } } //Case 2: There are no level cap for vertices (max level = 2), and there exists at least 1 vertex upgraded to Lv2 (as having no Lv2 while having to pick all vertices on the XY path will //return an answer that is equally as good as that of case 1 at best Budget=K; //Since at least 1 Lv2 vertex exists, there must be a point reachable from both X and Y => every single point on the XY - path must be reachable by at least 1 city for(int i=0;i<XYPath.size();i++){ Budget-=Cost1[XYPath[i]]; check[XYPath[i]]=1; ans2++; } tans=ans1; /* pq1: For all "single" upgrades that can be done without further consequences. Works with all upgrades to Type 0 vertices and the remaining (from Lv1 to 2) upgrades for type 2 vertices pq2: For all upgrades done to Type 1 vertices. Uses for optimiality comparasions with the 2 most optimal upgrades in pq1 pq3: For finding the cheapest single vertex of type 1 that will be upgraded to Lv1 (if it does exist) */ if(Budget>0){ for(int i=0;i<n;i++){ if(Type[i]==0){ pq1.push({-Cost1[i],i}); pq1.push({-Cost2[i],i}); }else if(Type[i]==1){ pq2.push({-(Cost1[i]+Cost2[i]),i}); pq3.push({-Cost1[i],i}); }else{ pq1.push({-Cost2[i],i}); } } //Just comparing stuffs. This part is for when you have 2 choices: Either do the 2 cheapest Type1 upgrade (consequence free) or maxxing out a Type 1 vertex (bring it from lv0 to lv2) while(!pq2.empty()&&Budget+pq2.top().first>=0){ /* If there is only 1 Type 1 upgrade left, use all Type 2 upgrades that we can still use : - If there are still some budget left after picking all pickable Type 1 vertices (to bump to lv2 instantly), we can still upgrade this last Type 0/2 vertex - Otherwise, it is already the current optimal answer (can't pick a type 1 vertex to max out (no budget left), can't even pick the cheapest possible Type1 upgrade => there's literally nothing you can do, that's all you could pick). No further upgrade can be made - aside from upgrading 1 Type 1 vertex to Lv1 */ if(pq1.size() <=1){ Budget+=pq2.top().first; if(Budget>=0){ check[pq2.top().second]=2; pq2.pop(); ans2+=2; continue; } } /* Comparing the cost for either: Doing the 2 cheapest "consequences free" upgrade (Type1 upgrades), or maxxing out the cheapest Type1 vertex. If maxxing out the cheapest Type1 vertex is cheaper, then immediately max it out. Otherwise, if doing both of the 2 cheapest Type1 upgrades are cheaper than maxxing out the cheapest Type1 vertext, do the cheapest Type1 upgrade possible, then try to compare the 2 scenarios again The "if Budget>=0" is just to check whether the upgrade is actually possible or not, in all cases */ tpos=pq1.top(); pq1.pop(); if(pq1.top().first+tpos.first> pq2.top().first&&Budget+tpos.first>=0){ Budget+=(tpos.first); ans2+=1; check[tpos.second]++; }else if(pq2.top().first+Budget>=0){ Budget+=pq2.top().first; pq1.push(tpos); ans2+=2; check[pq2.top().second]=2; pq2.pop(); } } //After the previous phase, there is no longer a pickable Type 1 vertex to max out. From this point on, greedily pick the cheapest remaining availible upgrades from those in pq1 while(!pq1.empty()&&Budget+pq1.top().first>=0){ Budget+=pq1.top().first; ans2++; check[pq1.top().second]++; pq1.pop(); } while(!pq3.empty()&&check[pq3.top().second]!=0){ pq3.pop(); } //And there's at most 1 Type 1 vertex that should be upgraded to lv1 in an optimal answer, so take the cheapest one (that hasn't been through any upgrade yet) and see whether it is //"upgradable" or not if(!pq3.empty()&&pq3.top().first+Budget>=0){ ans2++; check[pq3.top().second]=1; } //bruh tans=max(ans1,ans2); } return tans; }

Compilation message (stderr)

closing.cpp: In function 'int max_score(int, int, int, long long int, std::vector<int>, std::vector<int>, std::vector<int>)':
closing.cpp:81:12: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   81 |   while(cur<CList.size()){
      |         ~~~^~~~~~~~~~~~~
closing.cpp:83:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<edge>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   83 |    for(int i=0;i<adj[t].size();i++){
      |                ~^~~~~~~~~~~~~~
closing.cpp:101:12: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  101 |   while(cur<CList.size()){
      |         ~~~^~~~~~~~~~~~~
closing.cpp:103:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<edge>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  103 |    for(int i=0;i<adj[t].size();i++){
      |                ~^~~~~~~~~~~~~~
closing.cpp:130:16: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  130 |   for(int i=0;i<XYPath.size();i++){
      |               ~^~~~~~~~~~~~~~
closing.cpp:153:16: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  153 |   for(int i=0;i<XYPath.size();i++){
      |               ~^~~~~~~~~~~~~~
closing.cpp:27:6: warning: unused variable 'x' [-Wunused-variable]
   27 |  int x=X;
      |      ^
closing.cpp:28:6: warning: unused variable 'y' [-Wunused-variable]
   28 |  int y=Y;
      |      ^
closing.cpp:29:12: warning: unused variable 'k' [-Wunused-variable]
   29 |  long long k=K;
      |            ^
closing.cpp:30:6: warning: unused variable 'q' [-Wunused-variable]
   30 |  int q,s,e;
      |      ^
closing.cpp:33:10: warning: variable 'cur2' set but not used [-Wunused-but-set-variable]
   33 |  int cur,cur2;
      |          ^~~~
closing.cpp:35:12: warning: unused variable 't2' [-Wunused-variable]
   35 |  long long t2;
      |            ^~
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...