Submission #1040841

#TimeUsernameProblemLanguageResultExecution timeMemory
1040841Dan4LifeFountain Parks (IOI21_parks)C++17
70 / 100
313 ms121612 KiB
#include "parks.h"
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define sz(a) (int)a.size()
#define all(a) begin(a),end(a)
using vi = vector<int>;
using ll = long long;
using ar2 = array<int,2>;
using ar3 = array<int,3>;

const int mxN = (int)2e5+10;
int n;
struct Edge{
	int fa, fb, x, y;
	Edge(int a=0, int b=0, int _x=-1, int _y=-1){
		fa=a, fb=b, x=_x, y=_y;
	}
};
vector<Edge> edges;
vector<ar3> fountains, origFountains;
vector<int> adj[mxN];
set<ar2> usedB;

template<int SZ> struct DSU{
	int p[SZ];
	vector<int> comp[SZ];
	void init(int n){
		for(int i = 0; i < n; i++){
			p[i]=i; comp[i].clear();
			comp[i].pb(i);
		}
	}
	
	int findSet(int i){return p[i]==i?i:p[i]=findSet(p[i]);}
	bool isSameSet(int i, int j) {return findSet(i)==findSet(j);}
	void unionSet(int i, int j){
		int x = findSet(i), y = findSet(j);
		if(x==y) return;
		adj[i].pb(j); adj[j].pb(i);
		if(sz(comp[x]) < sz(comp[y])) swap(x,y);
		p[y]=x; for(auto u : comp[y]) comp[x].pb(u);
	}
	int findSz(int i) { return sz(comp[findSet(i)]); }
};
DSU<mxN> dsu;

set<int> horEdge[mxN], verEdge[mxN];

void dfs(int s, int p, bool turn){
	if(p!=-1){
		if(origFountains[s][0]==origFountains[p][0]){
			int x = origFountains[s][0], y = min(origFountains[s][1],origFountains[p][1])+1;
			int x1 = x-1, x2 = x+1;
			if(!turn) verEdge[x].insert(y-1);
			else{
				bool ok = 0;
				if(horEdge[y-1].count(x-2) and usedB.count({x1,y-2})) ok=1;
				if(horEdge[y+1].count(x-2) and usedB.count({x1,y+2})) ok=1;
				if(ok) swap(x1,x2);
				
				if(usedB.count({x1,y})) swap(x1,x2);
				if(usedB.count({x1,y})){ dsu.init(n); return; }
				edges.pb(Edge(s,p,x1,y)); usedB.insert({x1,y});
				verEdge[x].erase(y-1);
			}
		}
		else{
			int x = min(origFountains[s][0],origFountains[p][0])+1, y = origFountains[s][1];
			int y1 = y-1, y2 = y+1;
			if(!turn) horEdge[y].insert(x-1);
			else{
				bool ok = 0;
				if(verEdge[x-1].count(y-2) and usedB.count({x-2,y1})) ok=1;
				if(verEdge[x+1].count(y-2) and usedB.count({x+2,y1})) ok=1;
				if(ok) swap(y1,y2);
				
				if(usedB.count({x,y1})) swap(y1,y2);
				if(usedB.count({x,y1})){ dsu.init(n); return; }
				edges.pb(Edge(s,p,x,y1)); usedB.insert({x,y1});
				horEdge[y].erase(x-1);
			}
		}
	}
	for(auto u : adj[s]){
		if(u==p) continue;
		dfs(u,s,turn);
	}
}

int construct_roads(vi x, vi y) {
	n = sz(x); dsu.init(n);
	if (n==1){ build({}, {}, {}, {}); return 1; }
	int mnX = *min_element(all(x));
	int mxX = *max_element(all(x));
	for(int i = 0; i < n; i++){
		fountains.pb({x[i],y[i],i});
		origFountains.pb({x[i],y[i],i});
	}
	
	if(mnX==mxX){
		sort(all(fountains),[&](ar3 a, ar3 b){ return a[1]<b[1]; });
		for(int i = 1; i < sz(fountains); i++){
			if(fountains[i][1]-fountains[i-1][1]==2){
				auto [x1,y1,a] = fountains[i-1];
				auto [x2,y2,b] = fountains[i];
				dsu.unionSet(a,b);
				edges.pb(Edge(a,b,x1-1,y1+1));
			}
		}
	}
	else if(mxX-mnX==2){
		sort(all(fountains),[&](ar3 a, ar3 b){ 
			if(a[0]!=b[0]) return a[0]<b[0];
			return a[1]<b[1]; 
		});
		set<ar2> S; S.clear();
		for(int i = sz(fountains)-1; i>=0; i--){
			if(fountains[i][0]!=mxX) break;
			S.insert({fountains[i][1], fountains[i][2]});
		}
		for(int i = 1; i < sz(fountains); i++){
			if(fountains[i][0]!=fountains[i-1][0]) continue;
			if(fountains[i][1]-fountains[i-1][1]==2){
				auto [x1,y1,a] = fountains[i-1];
				auto [x2,y2,b] = fountains[i];
				dsu.unionSet(a,b);
				if(x1==mnX) edges.pb(Edge(a,b,x1-1,y1+1));
				else edges.pb(Edge(a,b,x1+1,y1+1));
			}
		}
		
		for(int i = 0; i < sz(fountains); i++){
			auto [x1,y1,a] = fountains[i];
			if(x1!=mnX) break;
			auto itr = S.lower_bound({y1,-1});
			if(itr==end(S) or (*itr)[0]!=y1) continue;
			int b = (*itr)[1];
			dsu.unionSet(a,b);
			edges.pb(Edge(a,b,x1+1,y1-1));
		}
	}
	else if(mxX-mnX==4){
		sort(all(fountains),[&](ar3 a, ar3 b){ 
			if(a[0]!=b[0]) return a[0]<b[0];
			return a[1]<b[1]; 
		});
		set<ar2> S[mxN];
		for(int i = sz(fountains)-1; i>=0; i--)
			S[fountains[i][0]].insert({fountains[i][1], fountains[i][2]});
		for(int i = 1; i < sz(fountains); i++){
			if(fountains[i][0]!=fountains[i-1][0]) continue;
			if(fountains[i][1]-fountains[i-1][1]==2){
				auto [x1,y1,a] = fountains[i-1];
				auto [x2,y2,b] = fountains[i];
				dsu.unionSet(a,b);
				if(x1==mnX) edges.pb(Edge(a,b,x1-1,y1+1)), usedB.insert({x1-1,y1+1});
				else if(x1==mxX) edges.pb(Edge(a,b,x1+1,y1+1)), usedB.insert({x1+1,y1+1});
				else edges.pb(Edge(a,b,y1%4==0?x1-1:x1+1,y1+1)), usedB.insert({y1%4==0?x1-1:x1+1,y1+1});
			}
		}
		for(int i = 0; i < sz(fountains); i++){
			auto [x1,y1,a] = fountains[i];
			auto itr = S[x1+2].lower_bound({y1,-1});
			if(itr==end(S[x1+2]) or (*itr)[0]!=y1) continue;
			int b = (*itr)[1];
			
			if(!usedB.count({x1+1,y1-1})){
				dsu.unionSet(a,b);
				edges.pb(Edge(a,b,x1+1,y1-1));
				usedB.insert({x1+1,y1-1});
			}
			else if(!usedB.count({x1+1,y1+1})){
				dsu.unionSet(a,b);
				edges.pb(Edge(a,b,x1+1,y1+1));
				usedB.insert({x1+1,y1+1});
			}			
		}
	}
	else{
		sort(all(fountains),[&](ar3 a, ar3 b){ 
			if(a[0]!=b[0]) return a[0]<b[0];
			return a[1]<b[1]; 
		});
		set<ar2> S[mxN];
		for(int i = sz(fountains)-1; i>=0; i--)
			S[fountains[i][0]].insert({fountains[i][1], fountains[i][2]});
		for(int i = 1; i < sz(fountains); i++){
			if(fountains[i][0]!=fountains[i-1][0]) continue;
			if(fountains[i][1]-fountains[i-1][1]==2){
				auto [x1,y1,a] = fountains[i-1];
				auto [x2,y2,b] = fountains[i];
				dsu.unionSet(a,b);
			}
		}
		for(int i = 0; i < sz(fountains); i++){
			auto [x1,y1,a] = fountains[i];
			auto itr = S[x1+2].lower_bound({y1,-1});
			if(itr==end(S[x1+2]) or (*itr)[0]!=y1) continue;
			int b = (*itr)[1];
			dsu.unionSet(a,b);
		}
		for(int i = 0; i < n; i++){
			if(sz(adj[i])!=1) continue;
			dfs(i,-1, 0); dfs(i,-1, 1); break;
		}
	}
	if(dsu.findSz(0)!=n) return 0;
    vi U, V, A, B;
    for(auto edge : edges){
		U.pb(edge.fa), V.pb(edge.fb);
		A.pb(edge.x), B.pb(edge.y);
	}
	build(U,V,A,B); return 1;
}
#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...