제출 #1342671

#제출 시각아이디문제언어결과실행 시간메모리
1342671garam1732식물 비교 (IOI20_plants)C++20
44 / 100
628 ms32248 KiB
#ifndef LOCAL
#include "plants.h"
#endif
#include <bits/stdc++.h>
using namespace std;

#define ff first
#define ss second
#define bl ' '
#define endl '\n'
#define all(v) (v).begin(), (v).end()
#define comp(v) (v).erase(unique(all(v)), (v).end())
#define lbd(v,x) lower_bound(all(v), (x))-(v).begin()
#define ubd(v,x) upper_bound(all(v), (x))-(v).begin()
#define sz(v) ((int)(v).size())

typedef long long ll;
typedef pair<int, int> pi;
typedef pair<pi, int> pii;
typedef pair<int, pi> ipi;
typedef pair<pi, pi> pipi;
typedef pair<ll, ll> pll;

const int MAXN = 100100*2;
const ll MOD = 1e9+7;
const ll INF = 2e9;

struct SegTree {
    pi tree[MAXN*4]; // (r, index)
    pi lazy[MAXN*4]; // (0, diff), (1, set)

    void init(int node, int s, int e, vector<int>& r) {
        if(s==e) {
            tree[node] = {r[s], s};
            return;
        }

        int mid=s+e>>1;
        init(node<<1,s,mid,r); init(node<<1|1,mid+1,e,r);
        tree[node] = min(tree[node<<1], tree[node<<1|1]);
    }

    void cal(pi &x, pi a) {
        if(a.ff == 1) x = a;
        else if(!(x==pi(1,MAXN))) x.ss += a.ss;
    }

    void prop(int node, int s, int e) {
        if(lazy[node].ff == 0) { if(tree[node].ff^MAXN) tree[node].ff += lazy[node].ss;}
        else tree[node].ff = lazy[node].ss;

        if(s!=e) {
            for(int x:{node<<1, node<<1|1}) 
                cal(lazy[x], lazy[node]);
        } lazy[node] = {0,0};
    }

    void update(int node, int s, int e, int l, int r, pi val) {
        prop(node, s, e);
        if(e<l || r<s) return;
        if(l<=s && e<=r) {
            cal(lazy[node], val);
            prop(node, s, e); return;
        }
        
        int mid=s+e>>1;
        update(node<<1,s,mid,l,r,val); update(node<<1|1,mid+1,e,l,r,val);
        tree[node] = min(tree[node<<1], tree[node<<1|1]);
    }

    pi solve(int node, int s, int e) {
        prop(node, s, e); return tree[1];
    }

    pi f(int node, int s, int e, int l, int r) {
        prop(node,s,e);
        if(e<l || r<s) return {MAXN,MAXN};
        if(l<=s && e<=r) return tree[node];

        int mid=s+e>>1;
        return min(f(node<<1,s,mid,l,r), f(node<<1|1,mid+1,e,l,r));
    }
} seg;

int K, n;
set<int> s, rs;
void f(int a, int b) {
    int d = (b+n-a)%n; if(d==0) d=n;
    if(d >= K) {
        if(rs.find(b) == rs.end()) rs.insert(b);
        else rs.erase(b);
    }
}
void ins(int x) {
    if(s.empty()) {
        s.insert(x);
        rs.insert(x);
        return;
    }

    auto itr = s.lower_bound(x);
    if(itr == s.end()) itr = s.begin();
    auto itl = s.lower_bound(x);
    if(itl == s.begin()) itl = prev(s.end());
    else itl = prev(itl);

    f(*itl, *itr); f(*itl, x); f(x, *itr);
    s.insert(x);
} void rmv(int x) {
    if(sz(s) == 1) {
        s.erase(x);
        rs.erase(x);
        return;
    }

    auto it = s.find(x);
    auto itr = (next(it)==s.end() ? s.begin() : next(it));
    auto itl = (it==s.begin() ? prev(s.end()) : prev(it));

    f(*itl, *it); f(*it, *itr); f(*itl, *itr);
    s.erase(it);
}

int lev[MAXN];
int L[MAXN], R[MAXN]; // smallest level greater then itself among k-1 left/right elements
int Ldst[MAXN], Rdst[MAXN];
bool vst[MAXN];
set<pi> ks;

void dfs1(int here) {
    vst[here] = 1;
    if(R[here]==0) {
        Rdst[here] = 0;
        return;
    }

    int there = (here + R[here])%n;
    if(!vst[there]) dfs1(there);
    Rdst[here] = R[here] + Rdst[there];
} void dfs2(int here) {
    vst[here] = 1;
    if(L[here]==0) {
        Ldst[here] = 0;
        return;
    }

    int there = (here + n-L[here])%n;
    if(!vst[there]) dfs2(there);
    Ldst[here] = L[here] + Ldst[there];
};

void init(int k, std::vector<int> r) {
    n = r.size(); int cnt=0; K = k;

    // init seg -> r
    // each loop, pick min (r, index) -> if r=0, store in a set and delete from segtree
    // make another set, managing elements whose left k-1 elements are not in the origin set
    // assign new level to the managing set, delete from the set / update segtree
    seg.init(1,0,n-1,r);
    int rem=n;
    while(rem) {
        while(1) {
            auto [a,x] = seg.solve(1,0,n-1);
            if(a>0) break;

            ins(x);
            seg.update(1,0,n-1,x,x,{1,MAXN});
        }

        vector<int> tmp={}; cnt++;
        for(int x:rs) tmp.push_back(x);
        for(int x:tmp) {
            rem--;
            rmv(x); lev[x] = cnt;

            if(x-k+1 >= 0) seg.update(1,0,n-1,x-k+1,x-1,{0,-1});
            else {
                seg.update(1,0,n-1,0,x-1,{0,-1});
                seg.update(1,0,n-1,x-k+1+n,n-1,{0,-1});
            }
        }
    }

    // construct jump table
    for(int j=1;j<k;j++) ks.insert({lev[j],j});
    {
        auto it = ks.lower_bound({lev[0],0});
        if(it == ks.end()) R[0] = 0;
        else R[0] = it->ss;
    } for(int i=1;i<n;i++) {
        ks.erase({lev[i],i});
        ks.insert({lev[(i+k-1)%n], (i+k-1)%n});
        auto it = ks.lower_bound({lev[i],0});
        if(it == ks.end()) R[i] = 0;
        else R[i] = (it->ss-i+n)%n;
    }

    ks.clear();
    for(int j=n-2;j>=n-k;j--) ks.insert({lev[j],j});
    {
        auto it = ks.lower_bound({lev[n-1],0});
        if(it == ks.end()) L[n-1] = 0;
        else L[n-1] = (n-1 - it->ss)%n;
    } for(int j=n-2;j>=0;j--) {
        ks.erase({lev[j],j});
        ks.insert({lev[(j-k+1+n)%n], (j-k+1+n)%n});
        auto it = ks.lower_bound({lev[j],0});
        if(it == ks.end()) L[j] = 0;
        else L[j] = (j - it->ss + n)%n;
    }

    for(int i=0;i<n;i++) vst[i]=0;
    for(int i=0;i<n;i++) if(!vst[i]) dfs1(i);

    for(int i=0;i<n;i++) vst[i]=0;
    for(int i=0;i<n;i++) if(!vst[i]) dfs2(i);
}

bool check(int x, int y) { // is there a path from x to y?
    if(Rdst[x] >= (y-x+n)%n) return 1;
    if(Ldst[x] >= (x-y+n)%n) return 1;
    return 0;
}

int compare_plants(int x, int y) {
    if(lev[x] == lev[y]) return 0;

    int res=1;
    if(lev[x] > lev[y]) swap(x,y),res=-1;
    //if(!check(x,y)) res=0;
    return res;
}

#ifdef LOCAL
// grader
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;
}
#endif
#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...