Submission #477127

#TimeUsernameProblemLanguageResultExecution timeMemory
477127blueComparing Plants (IOI20_plants)C++17
0 / 100
1 ms332 KiB
#include "plants.h"
#include <vector>
#include <iostream>
using namespace std;

int N;
int K;

const long long INF = 1e9;
const int logN = 19;

vector< vector<int> > edge;
vector<int> ht;

int dist(int x, int y) //clockwise distance from x to y
{
	x = x % N;
	y = y % N;
	if(y < x) y += N;
	return y-x;
}

struct segtree
{
	int l;
	int r;

	pair<long long, int> mn; //min first, index second
	pair<long long, int> mx; //max first, index second
	int lp = 0;

	segtree* left = NULL;
	segtree* right = NULL;

	segtree()
	{
		;
	}

	segtree(int L, int R)
	{
		l = L;
		r = R;

		mn = make_pair(0, l);
		mx = make_pair(0, l);

		if(l == r) return;

		int m = (l+r)/2;

		left = new segtree(l, m);
		right = new segtree(m+1, r);
	}

	void add(int L, int R, long long V)
	{
		L = (L + 10*N) % N;
		R = (R + 10*N) % N;


		if(R < L)
		{
			add(L, N-1, V);
			add(0, R, V);
			return;
		}

		if(R < l || r < L) return;
		else if(L <= l && r <= R)
		{
			lp += V;
			mn.first += V;
			mx.first += V;
		}
		else
		{
			left->add(L, R, V);
			right->add(L, R, V);

			mn = min(left->mn, right->mn);
			mn.first += lp;

			mx = max(left->mx, right->mx);
			mx.first += lp;
		}
	}

	pair<long long, int> rangemin(int L, int R)
	{
		L = (L + 10*N) % N;
		R = (R + 10*N) % N;

		if(R < L)
		{
			return min(rangemin(L, N-1), rangemin(0, R));
		}

		if(R < l || r < L) return make_pair(+2*INF, -1);
		else if(L <= l && r <= R)
		{
			return mn;
		}
		else
		{
			pair<long long, int> A = min(left->rangemin(L, R), right->rangemin(L, R));
			A.first += lp;
			return A;
		}
	}

	pair<long long, int> rangemax(int L, int R)
	{
		L = (L + 10*N) % N;
		R = (R + 10*N) % N;

		if(R < L)
		{
			return max(rangemax(L, N-1), rangemax(0, R));
		}

		if(R < l || r < L) return make_pair(-2*INF, -1);
		else if(L <= l && r <= R)
		{
			return mx;
		}
		else
		{
			pair<long long, int> A = max(left->rangemax(L, R), right->rangemax(L, R));
			A.first += lp;
			// cerr << "returning " << A.first << ' ' << A.second << " for rangemax " << L << ' ' << R << '\n';
			return A;
		}
	}
};

segtree R;
vector<int> pos;




vector< vector<int> > right_suc;
vector< vector<int> > left_suc;


void init(int k, vector<int> r)
{
	N = r.size();
	K = k;


	segtree R(0, N-1);             //R stores the array r, if an index is dead its value is INF

	segtree S(0, N-1);			  //S[i] is equal to the number of indices j in [i-K, i-1] that have R[j] >= 1
	                              //                                                             including dead
								  //If the index i is dead, S[i] is equal to -1.

	/*
		R: if index i is alive, R[i] = r[i]
		   if index i is dead, R[i] = >=INF

		S: if index i is alive:
				if R[i] == 0:
					S[i] = #(j in [i-K, i-1], R[j] >= 1) (including dead stuff)
				else:
					S[i] = -INF + #(j in [i-K, i-1], R[j] >= 1)
		   if index i is dead: S[i] = -INF + ?
	*/

	vector<int> h_greedy;

	for(int i = 0; i < N; i++)
	{
		R.add(i, i, +r[i]);

		if(r[i] >= 1)
			S.add(i+1, i+K-1, +1);

		if(r[i] != 0)
			S.add(i, i, -INF);
	}
	// cerr << "check\n";
	// for(int i = 0; i < N; i++) cerr << R.rangemin(i, i).first << ' ' << R.rangemin(i, i).second << '\n';
	// cerr << '\n';





	for(int t = 0; t < N; t++)
	{
		// cerr << "\n\n";
		// for(int i = 0; i < N; i++) cerr << S.rangemax(i, i).first << ' ' << S.rangemax(i, i).second << " | ";
		// cerr << '\n';
		// for(int i = 0; i < N; i++) cerr << R.rangemax(i, i).first << ' ' << R.rangemax(i, i).second << " | ";
		// cerr << '\n';
		// cerr << "t = " << t << ", ";
		// cerr << "IMPORTANT CALL!\n";
		// cerr << S.mx.first << ' ' << S.mx.second << '\n';
		pair<long long, int> p = S.rangemax(0, N-1);
		int I = p.second;
		h_greedy.push_back(I);
		// cerr << "I = " << I << '\n';

		R.add(I, I, +INF);
		S.add(I, I, -INF);
		S.add(I+1, I+K-1, +1);


		vector<int> newzeros;
		// R.add(I+1, I+K-1, -1);
		R.add(I-K+1, I-1, -1);
		while(1)
		{
			// for(int i = 0; i < N; i++) cerr << R.rangemin(i, i).second << ' ';
			// cerr << '\n';


			pair<long long, int> q = R.rangemin(I-K+1, I-1);
			if(q.first > 0) break;
			// cerr << "q = " << q.second << '\n';
			newzeros.push_back(q.second);
			R.add(q.second, q.second, +1);
		}
		for(int z: newzeros)
		{
			R.add(z, z, -1);
			S.add(z, z, +INF);
		}

		for(int z: newzeros)
			S.add(z+1, z+K-1, -1);
	}


	// for(int h: h_greedy) cerr << h << ' ';
	// cerr << '\n';


	pos = vector<int>(N); //height position, 0 = highest height
	for(int i = 0; i < N; i++)
		pos[ h_greedy[i] ] = i;

	ht = vector<int>(N);
	for(int i = 0; i < N; i++)
		ht[i] = N-1 - pos[i];

	for(int i = 0; i < N; i++)
		pos[ ht[i] ] = i;


	for(int i = 0; i < N; i++)
	{
		right_suc[i] = vector<int>(1+logN);
		left_suc[i] = vector<int>(1+logN);
	}

	segtree ST(0, N-1);
	for(int i = 0; i < N; i++) S.add(i, i, +1'000'000);

	for(int h = N-1; h >= 0; h--)
	{
		pair<long long, int> lft = S.rangemin(pos[h] - K + 1, pos[h] - 1);
		if(lft.first >= 1'000'000)
			left_suc[pos[h]][0] = pos[h];
		else
			left_suc[pos[h]][0] = lft.second;

		pair<long long, int> rgt = S.rangemin(pos[h] + 1, pos[h] + K - 1);
		if(rgt.first >= 1'000'000)
			right_suc[pos[h]][0] = pos[h];
		else
			right_suc[pos[h]][0] = rgt.second;

		S.add(pos[h], pos[h], -1'000'000 + h);
	}

	for(int e = 1; e <= logN; e++)
		for(int i = 0; i < N; i++)
		{
			left_suc[i][e] = left_suc[ left_suc[i][e-1] ][e-1];
			right_suc[i][e] = right_suc[ right_suc[i][e-1] ][e-1];
		}
}

bool query_left(int x, int y) //check if there is increasing path from x to y
{
	for(int e = logN; e >= 0; e--)
	{
		if(ht[ left_suc[x][e] ] > ht[y]) continue;
		if(dist(y, x) > dist(left_suc[x][e], x) + dist(y, left_suc[x][e])) continue;
		x = left_suc[x][e];
	}
	return (min(dist(x, y), dist(y, x)) < K && ht[x] <= ht[y]);
}

bool query_right(int x, int y) //check if there is increasing path from x to y
{
	for(int e = logN; e >= 0; e--)
	{
		if(ht[ right_suc[x][e] ] > ht[y]) continue;
		if(dist(x, y) > dist(x, right_suc[x][e]) + dist(right_suc[x][e], y)) continue;
		x = right_suc[x][e];
	}
	return (min(dist(x, y), dist(y, x)) < K && ht[x] <= ht[y]);
}

int compare_plants(int x, int y)
{
	if(query_left(x, y)) return -1;
	else if(query_right(x, y)) return -1;
	else if(query_left(y, x)) return 1;
	else if(query_right(y, x)) return 1;
	else 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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...