Submission #434642

#TimeUsernameProblemLanguageResultExecution timeMemory
43464279brueComparing Plants (IOI20_plants)C++14
49 / 100
2397 ms104020 KiB
#include <bits/stdc++.h>
#include "plants.h"

using namespace std;

typedef long long ll;

struct segTree{
    pair<int, int> tree[1600002];
    int lazy[1600002];

    void init(int i, int l, int r, int *A){
        lazy[i] = 0;
        if(l==r){
            tree[i] = make_pair(A[l], l);
            return;
        }
        int m = (l+r)>>1;
        init(i*2, l, m, A);
        init(i*2+1, m+1, r, A);
        tree[i] = min(tree[i*2], tree[i*2+1]);
    }

    void propagate(int i, int l, int r){
        tree[i].first += lazy[i];
        if(l!=r){
            lazy[i*2] += lazy[i];
            lazy[i*2+1] += lazy[i];
        }
        lazy[i] = 0;
    }

    void add(int i, int l, int r, int s, int e, int val){
        propagate(i, l, r);
        if(r<s || e<l) return;
        if(s<=l && r<=e){
            lazy[i] += val;
            propagate(i, l, r);
            return;
        }
        int m = (l+r)>>1;
        add(i*2, l, m, s, e, val);
        add(i*2+1, m+1, r, s, e, val);
        tree[i] = min(tree[i*2], tree[i*2+1]);
    }

    pair<int, int> findMin(int i, int l, int r, int s, int e){
        propagate(i, l, r);
        if(r<s || e<l) return make_pair(INT_MAX, INT_MAX);
        if(s<=l && r<=e) return tree[i];
        int m = (l+r)>>1;
        return min(findMin(i*2, l, m, s, e), findMin(i*2+1, m+1, r, s, e));
    }
} tree;

struct mineSeg{
    struct Node {
        ll lmax; int lidx;
        ll rmax; int ridx;
        ll ans; int ansl, ansr;
        ll sum;

        Node(){}
        Node(ll x, int idx){
            lmax = rmax = ans = sum = x;
            lidx = ridx = ansl = ansr = idx;
        }

        Node merge(const Node &r)const{
            Node ret = *this;
            if(ret.lmax < sum + r.lmax){
                ret.lmax = sum + r.lmax;
                ret.lidx = r.lidx;
            }

            ret.rmax += r.sum;
            if(ret.rmax < r.rmax){
                ret.rmax = r.rmax;
                ret.ridx = r.ridx;
            }

            if(ret.ans < r.ans) ret.ans = r.ans, ret.ansl = r.ansl, ret.ansr = r.ansr;
            if(ret.ans < rmax + r.lmax){
                ret.ans = rmax + r.lmax;
                ret.ansl = ridx, ret.ansr = r.lidx;
            }

            ret.sum += r.sum;
            return ret;
        }
    } tree[1600002];

    void init(int i, int l, int r, int *A){
        if(l==r){
            tree[i] = Node(A[l] ? 1 : -1e9, l);
            return;
        }
        int m = (l+r)>>1;
        init(i*2, l, m, A);
        init(i*2+1, m+1, r, A);
        tree[i] = tree[i*2].merge(tree[i*2+1]);
    }

    void change(int i, int l, int r, int idx, int x){
        if(l==r){
            tree[i] = Node(x ? 1 : -1e9, l);
            return;
        }
        int m = (l+r)>>1;
        if(idx <= m) change(i*2, l, m, idx, x);
        else change(i*2+1, m+1, r, idx, x);
        tree[i] = tree[i*2].merge(tree[i*2+1]);
    }
} mineTree;

struct checkSeg{
    ll MIN[1600002], MAX[1600002];

    void init(int i, int l, int r){
        if(l==r){
            MIN[i] = 1e18;
            MAX[i] = -1e18;
            return;
        }
        int m = (l+r)>>1;
        init(i*2, l, m);
        init(i*2+1, m+1, r);
        MIN[i] = min(MIN[i*2], MIN[i*2+1]);
        MAX[i] = max(MAX[i*2], MAX[i*2+1]);
    }

    void update(int i, int l, int r, int idx, ll s, ll e){
        if(l==r){
            MIN[i] = s, MAX[i] = e;
            return;
        }
        int m = (l+r)>>1;
        if(idx <= m) update(i*2, l, m, idx, s, e);
        else update(i*2+1, m+1, r, idx, s, e);
        MIN[i] = min(MIN[i*2], MIN[i*2+1]);
        MAX[i] = max(MAX[i*2], MAX[i*2+1]);
    }

    pair<ll, ll> query(int i, int l, int r, int s, int e){
        if(r<s || e<l) return make_pair(1e18, -1e18);
        if(s<=l && r<=e) return make_pair(MIN[i], MAX[i]);
        int m = (l+r)>>1;
        pair<ll, ll> p1 = query(i*2, l, m, s, e), p2 = query(i*2+1, m+1, r, s, e);
        return make_pair(min(p1.first, p2.first), max(p1.second, p2.second));
    }
} chkseg;

int n, k;
int arr[400002];
int sum[400002];
int ans[400002];
int ord[400002];
ll L[400002], R[400002];

void init(int _k, vector<int> r) {
	n = (int)r.size();
	k = _k;
	for(int i=1; i<=n; i++) arr[i] = r[i-1];
	for(int i=n+1; i<=n*2; i++) arr[i] = arr[i-n];

    tree.init(1, 1, n*2, arr);
    mineTree.init(1, 1, n*2, arr);

    for(int turn=n; turn>=1; turn--){
        auto tmp = mineTree.tree[1];
        if(tmp.ans < k-1) exit(1);
        int loc = tmp.ansr % n + 1;
        ans[loc] = turn;
        ord[turn] = loc;

        /// 1에서 0이 되는 위치들을 검색
        int lim = loc+n, leftmost = lim-k+1;
        while(leftmost < lim){
            pair<int, int> tmp2 = tree.findMin(1, 1, n*2, leftmost, lim-1);
            if(tmp2.first > 1) break;
            int x = tmp2.second;
            mineTree.change(1, 1, n*2, (x-1)%n+1, 0);
            mineTree.change(1, 1, n*2, (x-1)%n+1+n, 0);
            leftmost = x+1;
        }
        mineTree.change(1, 1, n*2, loc, 1);
        mineTree.change(1, 1, n*2, loc+n, 1);

        /// tree 변경
        tree.add(1, 1, n*2, loc, loc, 1000000000);
        tree.add(1, 1, n*2, loc+n, loc+n, 1000000000);

        if(loc >= k){
            tree.add(1, 1, n*2, loc-k+1, loc, -1);
            tree.add(1, 1, n*2, loc-k+1+n, loc+n, -1);
        }
        else{
            tree.add(1, 1, n*2, 1, loc, -1);
            tree.add(1, 1, n*2, loc-k+1+n, loc+n, -1);
            tree.add(1, 1, n*2, 2*n-(k-loc)+1, n*2, -1);
        }
    }

    chkseg.init(1, 1, n*2);
    for(int turn=1; turn<=n; turn++){
        int x = ord[turn];
        chkseg.update(1, 1, n*2, x, x, x);
        chkseg.update(1, 1, n*2, x+n, x+n, x+n);

        L[x] = chkseg.query(1, 1, n*2, x+n-(k-1), x+n).first - n;
        R[x] = chkseg.query(1, 1, n*2, x, x+(k-1)).second;

        chkseg.update(1, 1, n*2, x, L[x], R[x]);
        chkseg.update(1, 1, n*2, x+n, L[x]+n, R[x]+n);
    }
}

int compare_plants(int x, int y) {
	x++, y++;
	int def = ans[x] > ans[y] ? 1 : -1;
	if(ans[x] < ans[y]) swap(x, y);

    ll l = L[x], r = R[x];
    if((r-l) >= n) return def;

    l = (n - (-l%n))%n;
    if(!l) l=n;

    r = (n - (-r%n))%n;
    if(!r) r=n;
    if(r<l) r+=n;

    if(l<=y && y<=r) return def;
    if(l<=y+n && y+n<=r) return def;
    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...