Submission #300638

#TimeUsernameProblemLanguageResultExecution timeMemory
300638imeimi2000Comparing Plants (IOI20_plants)C++17
100 / 100
921 ms47864 KiB
#ifdef imeimi

#include <vector>

void init(int k, std::vector<int> r);
int compare_plants(int x, int y);

#include <cstdio>
#include <cassert>
#include <vector>
#define n N
#define k K

static int n, k, q;
static std::vector<int> r;
static std:: vector<int> x;
static std:: vector<int> y;
static std:: vector<int> answer;
int main() {
	assert(scanf("%d%d%d", &n, &k, &q) == 3);
	r.resize(n);
	answer.resize(q);
	for (int i = 0; i < n; i++) {
		int value;
		assert(scanf("%d", &value) == 1);
		r[i] = value;
	}
	x.resize(q);
	y.resize(q);
	for (int i = 0; i < q; i++) {
		assert(scanf("%d%d", &x[i], &y[i]) == 2);
	}
	fclose(stdin);

	init(k, r);
	for (int i = 0; i < q; i++) {
		answer[i] = compare_plants(x[i], y[i]);
	}

	for (int i = 0; i < q; i++) {
		printf("%d\n", answer[i]);
	}

	fclose(stdout);

	return 0;
}

#undef n
#undef k
#else

#include "plants.h"

#endif

#include <bits/stdc++.h>

using namespace std;

namespace S {
    int seg[1 << 19], add[1 << 19];
    void update(int i, int s, int e, int x, int y, int v) {
        if (e < x || y < s) return;
        if (x <= s && e <= y) {
            seg[i] += v;
            add[i] += v;
            return;
        }
        int m = (s + e) / 2;
        update(i + i, s, m, x, y, v);
        update(i + i + 1, m + 1, e, x, y, v);
        seg[i] = min(seg[i + i], seg[i + i + 1]) + add[i];
    }
    int find(int i, int s, int e, int a = 0) {
        if (seg[i] + a) return 0;
        if (s == e) return s;
        a += add[i];
        int m = (s + e) / 2;
        int ret = find(i + i, s, m, a);
        if (ret) return ret;
        return find(i + i + 1, m + 1, e, a);
    }
}

static int n, k;
static int val[200001], rev[200001];
static int fen[200001], L[200001][18], R[200001][18];

static void update(int i, int x) {
    while (i <= n) {
        fen[i] += x;
        i += i & -i;
    }
}

static int query(int i) {
    int ret = 0;
    while (i) {
        ret += fen[i];
        i -= i & -i;
    }
    return ret;
}

static int find(int v) {
    int x = 0;
    for (int i = 18; i--; ) {
        int y = x + (1 << i);
        if (y <= n && fen[y] <= v) v -= fen[x = y];
    }
    return x + 1;
}

void init(int k, vector<int> r) {
    ::k = k;
    n = r.size();
    set<int> can, one;
    auto add = [&](int x) {
        S::update(1, 1, n, x, x, 1e8);
        auto it = can.insert(x).first;
        if (int(can.size()) == 1) {
            one.insert(x);
            return;
        }
        auto it1 = it;
        if (it1 == can.begin()) it1 = prev(can.end());
        else --it1;
        int d1 = (x - *it1 + n) % n;
        auto it2 = next(it);
        if (it2 == can.end()) it2 = can.begin();
        int d2 = (*it2 - x + n) % n;
        if (it1 == it2) {
            one.erase(*it2);
            if (d1 >= k) one.insert(x);
            if (d2 >= k) one.insert(*it2);
            return;
        }
        if (d1 + d2 >= k) one.erase(*it2);
        if (d1 >= k) one.insert(x);
        if (d2 >= k) one.insert(*it2);
    };
    auto del = [&](int x) {
        S::update(1, 1, n, x - k + 1, x, -1);
        S::update(1, 1, n, n + x - k + 1, n + x, -1);
        auto it1 = can.upper_bound(x);
        auto it2 = it1;
        can.erase(x);
        if (one.count(x)) one.erase(x);
        if (can.empty()) return;
        if (it1 == can.begin()) it1 = prev(can.end());
        else --it1;
        int d1 = (x - *it1 + n) % n;
        if (it2 == can.end()) it2 = can.begin();
        int d2 = (*it2 - x + n) % n;
        if (it1 == it2) {
            one.insert(*it2);
            return;
        }
        if (d2 >= k) one.erase(*it2);
        if (d1 + d2 >= k) one.insert(*it2);
    };
    for (int i = 1; i <= n; ++i) {
        S::update(1, 1, n, i, i, r[i - 1]);
    }
    for (int v = n; v > 0; --v) {
        int x;
        while (x = S::find(1, 1, n)) add(x);
        x = *one.begin();
        del(x);
        val[x] = v;
        rev[v] = x;
    }
    for (int i = n - k + 1; i <= n; ++i) update(val[i], 1);
    for (int i = 1; i <= n; ++i) {
        update(val[(i - k + n - 1) % n + 1], -1);
        int x = find(query(val[i]));
        L[i][0] = x <= n ? (i - rev[x] + n) % n : n;
        update(val[i], 1);
    }
    memset(fen, 0, sizeof(fen));
    for (int i = 1; i <= k; ++i) update(val[i], 1);
    for (int i = n; i > 0; --i) {
        update(val[(i + k + n - 1) % n + 1], -1);
        int x = find(query(val[i]));
        R[i][0] = x <= n ? (rev[x] - i + n) % n : n;
        update(val[i], 1);
    }
    for (int l = 1; l < 18; ++l) {
        for (int i = 1; i <= n; ++i) {
            int x = L[i][l - 1];
            L[i][l] = min(x + L[(i - x + n - 1) % n + 1][l - 1], n);
            x = R[i][l - 1];
            R[i][l] = min(x + R[(i + x - 1) % n + 1][l - 1], n);
        }
    }
}

bool goL(int x, int y) {
    int d = (x - y + n) % n;
    for (int i = 18; i--; ) {
        if (L[x][i] <= d) {
            d -= L[x][i];
            x = (x - L[x][i] + n - 1) % n + 1;
        }
    }
    return d < k && val[x] <= val[y];
}

bool goR(int x, int y) {
    int d = (y - x + n) % n;
    for (int i = 18; i--; ) {
        if (R[x][i] <= d) {
            d -= R[x][i];
            x = (x + R[x][i] - 1) % n + 1;
        }
    }
    return d < k && val[x] <= val[y];
}

bool go(int x, int y) {
    return goL(x, y) || goR(x, y);
}

int compare_plants(int x, int y) {
    if (go(x + 1, y + 1)) return -1;
    if (go(y + 1, x + 1)) return 1;
    return 0;
}

Compilation message (stderr)

plants.cpp: In function 'void init(int, std::vector<int>)':
plants.cpp:168:18: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
  168 |         while (x = S::find(1, 1, n)) add(x);
      |                ~~^~~~~~~~~~~~~~~~~~
#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...