#include #define pb push_back #define ff first #define ss second #define ll long long using namespace std; typedef pair pii; struct point{ int x,y,w; point(){} point(int x,int y,int w){ this->x=x; this->y=y; this->w=w; } }; namespace emst_namespace{ /** * Disjoint-set-union data structure */ class DSU { public: explicit DSU(size_t n = 0); size_t get_set(size_t x) const; bool is_in_same_set(size_t x, size_t y) const; void reset(size_t n); bool unite(size_t x, size_t y); private: mutable std::vector p; std::vector rank; }; DSU::DSU(size_t n) { reset(n); } size_t DSU::get_set(size_t x) const { return p[x] == x ? x : p[x] = get_set(p[x]); } bool DSU::is_in_same_set(size_t x, size_t y) const { return get_set(x) == get_set(y); } void DSU::reset(size_t n) { p.resize(n); rank.assign(n, 0); for (size_t i = 0; i < n; i++) { p[i] = i; } } bool DSU::unite(size_t x, size_t y) { size_t set_a = get_set(x); size_t set_b = get_set(y); if (set_a == set_b) { return false; } if (rank[set_a] > rank[set_b]) { std::swap(set_a, set_b); } if (rank[set_a] == rank[set_b]) { rank[set_b]++; } p[set_a] = set_b; return true; } /// DSU END /** * Point in DIM-dimensional space */ template class Point { public: Point(); const double & operator[](size_t i) const; double & operator[](size_t i); /** * Distance between two points */ template friend double distance(const Point & a, const Point & b); private: double data[DIM]; }; /** * Point with id */ template class UPoint : public Point { public: UPoint(const Point & ref, size_t id = 0); UPoint(size_t id = 0); size_t get_id() const; private: size_t id; }; /** * Bounding box in DIM-dimensional space */ template class AABB { public: AABB(); /** * Construct bounding box from vector iterator */ AABB(typename std::vector>::const_iterator iter, typename std::vector>::const_iterator end); /** * Size of the k-th dimension */ double size(size_t k) const; /** * Get the index of a dimension with the largest size */ size_t get_largest_dim() const; /** * Distance between two bounding boxes */ template friend double distance(const AABB & a, const AABB & b); private: Point minimal; Point maximal; }; // Implementation template Point::Point() { std::fill(data, data + DIM, 0.0); } template const double & Point::operator[](size_t i) const { return data[i]; } template double & Point::operator[](size_t i) { return data[i]; } template UPoint::UPoint(const Point & ref, size_t id) : Point(ref), id(id) {} template UPoint::UPoint(size_t id) :id(id) {} template size_t UPoint::get_id() const { return id; } template AABB::AABB() {} template AABB::AABB(typename std::vector>::const_iterator iter, typename std::vector>::const_iterator end) { minimal = maximal = *iter; for (; iter != end; ++iter) { for (size_t k = 0; k < DIM; k++) { minimal[k] = std::min(minimal[k], (*iter)[k]); maximal[k] = std::max(maximal[k], (*iter)[k]); } } } template double AABB::size(size_t k) const { return maximal[k] - minimal[k]; } template size_t AABB::get_largest_dim() const { size_t biggest_dim = 0; for (size_t k = 1; k < DIM; k++) { if (size(k) > size(biggest_dim)) biggest_dim = k; } return biggest_dim; } template double distance(const Point & a, const Point & b) { double distance_sqr = 0; for (size_t k = 0; k < DIM; k++) { double diff = a[k] - b[k]; distance_sqr += diff * diff; } return sqrt(distance_sqr); } template double distance(const AABB & a, const AABB & b) { double distance_sqr = 0; for (size_t k = 0; k < DIM; k++) { double diff = std::max(a.minimal[k], b.minimal[k]) - std::min(a.maximal[k], b.maximal[k]); if (diff > 0) { distance_sqr += diff * diff; } } return sqrt(distance_sqr); } ///Points done /** * K-d tree data structure */ template struct KdTree { public: KdTree(); /** * Construct K-d tree with height at most max_height from a given set of points */ KdTree(const std::vector> & points, size_t max_height); size_t get_root_id() const; size_t get_maximal_id() const; size_t get_left_child_id(size_t id) const; size_t get_right_child_id(size_t id) const; const AABB & get_bounding_box(size_t id) const; bool is_leaf(size_t id) const; typename std::vector>::const_iterator points_begin(size_t node_id) const; typename std::vector>::const_iterator points_end(size_t node_id) const; private: /** * K-d tree node. Represents part of space with points from (start) to (start+size-1) position in points array */ struct KdNode { KdNode() : start(0), is_leaf(false), size(0) {} AABB aabb; bool is_leaf; //is this node a leaf node and has no childs size_t start; size_t size; }; /** * Recursively build tree for current node node_id, for points from position (start) to position (start+size-1) */ void build(size_t node_id, size_t start, size_t size, size_t remaining_height); std::vector> points; std::vector nodes; }; // Implementation template KdTree::KdTree() {} template KdTree::KdTree(const std::vector> & points, size_t max_height) { this->points.reserve(points.size()); for (auto & p : points) { this->points.push_back(UPoint(p, this->points.size())); } nodes.resize(points.size() * 4); build(1, 0, points.size(), max_height); } template size_t KdTree::get_root_id() const { return 1; } template size_t KdTree::get_maximal_id() const { return (nodes.empty() ? 0 : nodes.size() - 1); } template size_t KdTree::get_left_child_id(size_t id) const { return id * 2; } template size_t KdTree::get_right_child_id(size_t id) const { return id * 2 + 1; } template bool KdTree::is_leaf(size_t id) const { return nodes[id].is_leaf; } template const AABB & KdTree::get_bounding_box(size_t id) const { return nodes[id].aabb; } template typename std::vector>::const_iterator KdTree::points_begin(size_t node_id) const { return points.begin() + nodes[node_id].start; } template typename std::vector>::const_iterator KdTree::points_end(size_t node_id) const { return points.begin() + nodes[node_id].start + nodes[node_id].size; } template void KdTree::build(size_t node_id, size_t start, size_t size, size_t remaining_height) { nodes[node_id].aabb = AABB(points.cbegin() + start, points.cbegin() + start + size); nodes[node_id].start = start; nodes[node_id].size = size; if (size == 1 || remaining_height == 0) { nodes[node_id].is_leaf = true; return; } size_t biggest = nodes[node_id].aabb.get_largest_dim(); std::nth_element(points.begin() + start, points.begin() + start + size / 2, points.begin() + start + size, [&biggest](const Point & a, const Point & b) { return a[biggest] < b[biggest]; }); // recursively call build for two parts build(node_id * 2, start, size / 2, remaining_height - 1); build(node_id * 2 + 1, start + size / 2, (size + 1) / 2, remaining_height - 1); } /// kd tree done typedef std::pair Edge; template class EmstSolver { public: EmstSolver() = default; const std::vector & get_solution() const { return solution; } const double & get_total_length() const { return total_length; } protected: std::vector solution; double total_length = 0.0; }; /** * Implementation of EMST algorithm using K-d tree * "Fast Euclidean Minimum Spanning Tree: Algorithm, Analysis, and Applications. William B. March, Parikshit Ram, Alexander G. Gray" * Time complexity: O(cNlogN), extra constant c depends on the distribution of points */ template class KdTreeSolver : public EmstSolver { public: explicit KdTreeSolver(const std::vector> & points) :num_points(points.size()) { dsu.reset(num_points); tree = KdTree(points, static_cast(floor(log2(num_points)) - 1)); is_fully_connected.assign(tree.get_maximal_id() + 1, false); solve(); // todo: clear containers } private: void solve() { auto & solution = EmstSolver::solution; auto & total_length = EmstSolver::total_length; while (solution.size() + 1 < num_points) { node_approximation.assign(tree.get_maximal_id() + 1, std::numeric_limits::max()); nearest_set.assign(num_points, { std::numeric_limits::max(), Edge(0,0) }); check_fully_connected(tree.get_root_id()); find_component_neighbors(tree.get_root_id(), tree.get_root_id()); for (size_t i = 0; i < num_points; i++) { if (i == dsu.get_set(i)) { Edge e = nearest_set[i].second; if (dsu.unite(e.first, e.second)) { solution.push_back(e); total_length += nearest_set[i].first; } } } } } void find_component_neighbors(size_t q, size_t r, size_t depth = 0) { if (is_fully_connected[q] && is_fully_connected[r] && dsu.is_in_same_set(tree.points_begin(q)->get_id(), tree.points_begin(r)->get_id())) { return; } if (distance(tree.get_bounding_box(q), tree.get_bounding_box(r)) > node_approximation[q]) { return; } if (tree.is_leaf(q) && tree.is_leaf(r)) { node_approximation[q] = 0.0; for (auto i = tree.points_begin(q); i != tree.points_end(q); i++) { for (auto j = tree.points_begin(r); j != tree.points_end(r); j++) { if (!dsu.is_in_same_set(i->get_id(), j->get_id())) { double dist = distance(*i, *j); if (dist < nearest_set[dsu.get_set(i->get_id())].first) { nearest_set[dsu.get_set(i->get_id())] = { dist, { i->get_id(), j->get_id() } }; } } } node_approximation[q] = std::max(node_approximation[q], nearest_set[dsu.get_set(i->get_id())].first); } } else { size_t qleft = tree.get_left_child_id(q); size_t qright = tree.get_right_child_id(q); size_t rleft = tree.get_left_child_id(r); size_t rright = tree.get_right_child_id(r); if (tree.is_leaf(q)) { find_component_neighbors(q, rleft, depth); find_component_neighbors(q, rright, depth); return; } if (tree.is_leaf(r)) { find_component_neighbors(qleft, r, depth); find_component_neighbors(qright, r, depth); node_approximation[q] = std::max(node_approximation[qleft], node_approximation[qright]); return; } find_component_neighbors(qleft, rleft, depth + 1); find_component_neighbors(qleft, rright, depth + 1); find_component_neighbors(qright, rright, depth + 1); find_component_neighbors(qright, rleft, depth + 1); node_approximation[q] = std::max(node_approximation[qleft], node_approximation[qright]); } } void check_fully_connected(size_t node_id) { if (is_fully_connected[node_id]) { return; } if (tree.is_leaf(node_id)) { bool fully_connected = true; for (auto iter = tree.points_begin(node_id); iter + 1 != tree.points_end(node_id); ++iter) { fully_connected &= dsu.is_in_same_set(iter->get_id(), (iter + 1)->get_id()); } is_fully_connected[node_id] = fully_connected; return; } size_t left = tree.get_left_child_id(node_id); size_t right = tree.get_right_child_id(node_id); check_fully_connected(left); check_fully_connected(right); if (is_fully_connected[left] && is_fully_connected[right] && dsu.is_in_same_set(tree.points_begin(left)->get_id(), tree.points_begin(right)->get_id())) { is_fully_connected[node_id] = true; } } size_t num_points; DSU dsu; KdTree tree; std::vector is_fully_connected; std::vector node_approximation; std::vector> nearest_set; }; /// emst done /** * Prim's algorithm * Time complexity: O(N^2) */ template class PrimSolver : public EmstSolver { public: PrimSolver(const std::vector> & points) { solve(points); } private: void solve(const std::vector> & points) { auto & solution = EmstSolver::solution; auto & total_length = EmstSolver::total_length; size_t num_points = points.size(); std::vector> distance_to_tree(num_points, { std::numeric_limits::max(), 0 }); std::vector used(num_points, false); used[0] = true; for (size_t i = 1; i < num_points; i++) { distance_to_tree[i] = { distance(points[0], points[i]), 0 }; } for (size_t iteration = 1; iteration < num_points; iteration++) { size_t nearest_id = 0; for (size_t i = 1; i < num_points; i++) { if (!used[i] && distance_to_tree[i] < distance_to_tree[nearest_id]) { nearest_id = i; } } solution.push_back({ nearest_id, distance_to_tree[nearest_id].second }); total_length += distance_to_tree[nearest_id].first; used[nearest_id] = true; for (size_t i = 1; i < num_points; i++) { if (!used[i] && distance(points[i], points[nearest_id]) < distance_to_tree[i].first) { distance_to_tree[i] = { distance(points[i], points[nearest_id]) , nearest_id }; } } } } }; /// prim done pair>> get_fast_mst_edges_and_score(vector&a){ vector>points(a.size()); for(int i=0;i solver_fast(points); vector>edges=solver_fast.get_solution(); vector> ret; for(int i=0;i>> get_fast_mst_edges_by_id_and_score(vector&a){ vector>points(a.size()); for(int i=0;i solver_fast(points); vector>edges=solver_fast.get_solution(); vector> ret; for(int i=0;i>> get_slow_mst_edges_and_score(vector&a){ vector>points(a.size()); for(int i=0;i solver_fast(points); vector>edges=solver_fast.get_solution(); vector> ret; for(int i=0;isoldiers,towers; namespace my_kdtree{ int wrong_cnt=0; struct my_kdt{ vectorpts; vector>tree; void build(int x,int l,int r,vector>&niz,int dep){ if(l>r)return; if(l==r){ tree[x].ff.ff=niz[l].ff; tree[x].ff.ss=1; tree[x].ss=1; return; } int mid=(l+r)/2; if(dep==0)sort(niz.begin()+l,niz.begin()+r+1,[](pair &a,pair &b){ return a.ss.x &a,pair &b){ return a.ss.y&pts){ this->pts=pts; tree.resize(4*pts.size()+1); vector>niz(pts.size()); for(int i=0;i&pom){ vectorpts(pom.size()); for(int i=0;ipts=pts; tree.resize(4*pts.size()+1); vector>niz(pts.size()); for(int i=0;iget_dist(target,pts[id]))best=id; } void nearest_neighbour(int x,point &target,int &best_id,int dep){ if(tree[x].ff.ss==0)return; int id=tree[x].ff.ff; int nxt_node,other_node; nxt_node=x*2; other_node=x*2+1; if(dep==0){ if(target.x<=pts[id].x){} else swap(nxt_node,other_node); } else{ if(target.y<=pts[id].y){} else swap(nxt_node,other_node); } if(tree[x].ss)update_best(target,best_id,id); nearest_neighbour(nxt_node,target,best_id,dep^1); ll pom=(target.x-(ll)pts[id].x)*(target.x-(ll)pts[id].x); if(dep)pom=(target.y-(ll)pts[id].y)*(target.y-(ll)pts[id].y); ///cout<pom){ nearest_neighbour(other_node,target,best_id,dep^1); wrong_cnt++; } } void delete_node(int x,point val,int dep){ int id=tree[x].ff.ff; if(pts[id].x==val.x && pts[id].y==val.y){ tree[x].ff.ss--; tree[x].ss--; return; } if(dep==0){ if(val.x<=pts[id].x)delete_node(x*2,val,dep^1); else delete_node(x*2+1,val,dep^1); } else{ if(val.y<=pts[id].y)delete_node(x*2,val,dep^1); else delete_node(x*2+1,val,dep^1); } tree[x].ff.ss=tree[x].ss+tree[x*2].ff.ss+tree[x*2+1].ff.ss; } }; } namespace TSP{ vectorvect[maxn]; int pos[maxn]; struct operation{ pii p1,p2; int w; }; struct gamestate{ map,int>pts; vectorops; double score; gamestate(vector&a,vector&b){ score=0; ops.clear(); for(int i=0;i=tow){ return ceil(sqrt((ll)sold*(ll)sold-(ll)tow*(ll)tow)); } else{ swap(sold,tow); return -ceil(sqrt((ll)sold*(ll)sold-(ll)tow*(ll)tow)); } } else{ return sold+tow; } } double static calc_dist(pii a,pii b){ return sqrt( ((ll)a.ff-b.ff)*((ll)a.ff-b.ff)+((ll)a.ss-b.ss)*((ll)a.ss-b.ss) ); } void do_operation(operation op){ map::iterator sit=pts.find(op.p1); if(sit==pts.end()){ cout<<"losa operacija"<ssss-=op.w; score+=op.w*calc_dist(op.p1,op.p2); pts[op.p2]=new_count(op.w,pts[op.p2]); ops.pb(op); } void ispis(){ cout<pts; vectorops; double score; gamestate_light(){} gamestate_light(vector&a){ score=0; ops.clear(); for(int i=0;i=tow){ return ceil(sqrt((ll)sold*(ll)sold-(ll)tow*(ll)tow)); } else{ swap(sold,tow); return -ceil(sqrt((ll)sold*(ll)sold-(ll)tow*(ll)tow)); } } else{ return sold+tow; } } double static calc_dist(pii a,pii b){ return sqrt( ((ll)a.ff-b.ff)*((ll)a.ff-b.ff)+((ll)a.ss-b.ss)*((ll)a.ss-b.ss) ); } void do_operation(operation op){ score+=op.w*calc_dist(op.p1,op.p2); if(op.w<=0){ cout<<"LOSA OPERACIJAAAAAAAAAAAAAAAAAAAA "<&a,gamestate_light &g){ if(a.size()==1){ return {a[0].x,a[0].y}; } ll xs,ys,cnt; xs=ys=cnt=0; for(int i=0;i&p){ p.pb(x); for(int i=0;i get_TSP(vector&a){ vectoredges=emst_namespace::get_fast_mst_edges_by_id_and_score(a).ss; for(int i=0;ipath; go_euler_tour_tree(0,-1,path); vectorret; for(int i=0;i&a,vector&b,gamestate_light &g){/// a -> moji vojnici if(a.size()==0 || b.size()==0)return; pii c=gathering_point(a,g); int curr=0; for(int i=0;ipath=get_TSP(b); for(int i=0;i get_greedy(vector&a,pii start){ my_kdtree::my_kdt ds(a); point s; s.x=start.ff; s.y=start.ss; vectorret; for(int i=0;i&a,vector&b,gamestate_light &g){/// a -> moji vojnici if(a.size()==0 || b.size()==0)return; pii c=gathering_point(a,g); int curr=0; for(int i=0;ipath=get_greedy(b,c); ///cout<<"done greedy"< pick_soldier_candidates_simple(vector&soldiers,vector&towers){ ll tower_sum=0; for(int i=0;iret; ll soldier_sum=0; for(int i=0;i=tower_sum)break; } return ret; } gamestate_light simple_example(vector soldiers,vector towers){ gamestate_light g(towers); vector cand=pick_soldier_candidates_simple(soldiers,towers); apply_TSP(cand,towers,g); return g; } gamestate_light simple_example_greedy(vector soldiers,vector towers){ gamestate_light g(towers); vector cand=pick_soldier_candidates_simple(soldiers,towers); apply_greedy(cand,towers,g); return g; } } namespace K_means{ mt19937 gen(10); const int max_c=1000000000; const int max_k=50000; ll tower_sqr_cnt[max_k]; ll sumx[max_k],sumy[max_k],cnt[max_k]; bool soldier_pos[maxn]; vector init_centroids(int k,vector&p){ vector ret(k); for(int i=0;i&c,vector&p){ for(int j=0;j get_K_centroids(int k,vector&p,int iter){ vectorcentroids=init_centroids(k,p); for(int i=0;i calc_sums(vector&soldiers,vector&towers){ ll sums=0; for(int i=0;i>&calcs){ for(int i=0;i&c,int id){ int ret=-1; ll mindist=-1; for(int i=0;i>&soldiers,vector>&towers,vector&c,vector>&calcs,int id,int id2){ for(int i=0;i>&soldiers,vector>&towers,vector&c){ vector>calcs(c.size()); for(int i=0;icurr_soldiers; bool cmp(int a,int b){ ///return get_dist(curr_soldiers[a],curr_centroid)&s,vector&p,int iter){ vectorcentroids=get_K_centroids(k,p,iter); /*for(int i=0;i>centroid_towers(k),centroid_soldiers(k); for(int i=0;iniz(s.size()); for(int i=0;itower_sqr_cnt[i])break; } ///cout<a,vectorb){ my_kdtree::my_kdt ds(a); ///sort(b.begin(),b.end(),tower_cmp); TSP::gamestate_light g(b); int soldier_sum=0; int tower_sum=0; for(int i=0;icand; int curr_sum=0; if(soldier_sum>=tower_sum)scale_coef=1; while(goal*scale_coef>(double)curr_sum){ int pom=-1; ds.nearest_neighbour(1,b[i],pom,0); ///cout<(double)curr_sum){ acnt--; ds.delete_node(1,a[pom],0); } } if(soldier_sum>=tower_sum){ //if(0==1){ pii gpoint=g.find_close_free_point(b[i].x,b[i].y); int cg=goal; for(int j=0;j0)g.do_operation(op); else ds.delete_node(1,a[lst],0); ///cout<>n>>m; soldiers.resize(n); towers.resize(m); for(int i=0;i>soldiers[i].x>>soldiers[i].y>>soldiers[i].w; } random_shuffle(soldiers.begin(),soldiers.end()); int maxw=0; for(int i=0;i>towers[i].x>>towers[i].y>>towers[i].w; maxw=max(maxw,towers[i].w); } random_shuffle(towers.begin(),towers.end()); if(maxw>4690)subtask=5; else if(maxw>1300)subtask=4; else if(maxw>360)subtask=3; else if(maxw>100)subtask=2; else subtask=1; ///pair>>pom=emst_namespace::get_fast_mst_edges_and_score(towers); /*pair>>pom=emst_namespace::get_fast_mst_edges_and_score(soldiers); cout<