Submission #1179627

#TimeUsernameProblemLanguageResultExecution timeMemory
1179627patgraModern Machine (JOI23_ho_t5)C++20
100 / 100
1059 ms79820 KiB
#include <bits/stdc++.h>

#define rep(a,b,c) for(auto a = (b); a != (c); a++)
#define repD(a,b,c) for(auto a = (b); a != (c); a--)
#define repIn(a, b) for(auto a : (b))
#define repIn2(a, b, c) for(auto [a, b] : (c))
#define repInAmp2(a, b, c) for(auto& [a, b] : (c))

constexpr bool dbg = 0;
#define DEBUG if constexpr(dbg)
#define DC DEBUG std::cerr
#define eol std::endl

#define ll long long
#define pb push_back

using namespace std;

constexpr int maxn = 12e4 + 7, maxTreeBase = 1 << 17, maxLog = 16, inf = 1e9 + 7;
int n, m;
bool ogRight[maxn], myRight[maxn];
int arr[maxn], prefSum[maxn];
vector<pair<pair<int, int>, int>> t[2 * maxTreeBase];
int treeBase;
int maxH1[maxn][maxLog], minH2[maxn][maxLog];
ll prefSumH1[maxn], prefSumH2[maxn];

constexpr int bufSize = 5* (60 + maxn * 2 + maxn * 10 + maxn * 2 * 10);
char buffer[bufSize];
int bufI;
void initBuffer() {
    fread_unlocked(buffer, sizeof(char), bufSize, stdin);
}
void getInt(int& x) {
    while(buffer[bufI] > '9' || buffer[bufI] < '0') bufI++;
    x = 0;
    while(buffer[bufI] <= '9' && buffer[bufI] >= '0') x = 10 * x + buffer[bufI] - '0', bufI++;
}

inline int getMaxH1(int l, int r) {
    if(l == r) return maxH1[l][0];
    int k = 31 - __builtin_clz(r - l + 1);
    return max(maxH1[l][k], maxH1[r - (1 << k) + 1][k]);
}
inline int getMinH2(int l, int r) {
    if(l == r) return minH2[l][0];
    int k = 31 - __builtin_clz(r - l + 1);
    return min(minH2[l][k], minH2[r - (1 << k) + 1][k]);
}

inline int truePrefSum(int l, int r, int x) {
    if(x <= l) return x;
    if(x >= r) return l + 1 + prefSum[r] - prefSum[l + 1];
    return l + 1 + prefSum[x] - prefSum[l + 1];
}
inline int cntRight(int l, int r, int il, int ir) {
    return truePrefSum(l, r, ir + 1) - truePrefSum(l, r, il);
}
inline int cntLeft(int l, int r, int il, int ir) {
    return (ir - il + 1) - cntRight(l, r, il, ir);
}

pair<int, int> f(int l, int r, int a) {
    DC << "f({" << l << ' ' << r << "}, " << a << "): " << eol << " ";
    int bl = cntRight(l, r, 0, a - 1);
    int br = cntLeft(l, r, a + 1, n - 1);
    DC << " bl = " << bl << "; br = " << br << eol;
    if(bl >= br) {
        // wylatujemy z prawej
        // pierwsze br wsrod bl przechodzi na br
        // szukamy ostatniego miejsca gdzie cntRight(0, a - 1) + br < bl
        DC << " przekabacamy " << br << " typow z lewej " << eol;
        int p = 0, s, k = a;

        bool xd = false;
        rep(xdd, 1, 2) if(p < a - xdd && cntRight(l, r, 0, a - 1 - xdd) + br < bl) { p = a - xdd; xd = true; break; }

        while(k - p > 1) {
            s = (p + k) / 2;
            if(cntRight(l, r, 0, s - 1) + br < bl) p = s;
            else k = s;
        }
        if(bl > br) p++;
        return {min(l, p - 1), p};
    }
    else {
        // wylatujemy z lewej
        // pierwsze bl + 1 wsrod br przechodzi na bl
        // szukamy pierwszego miejsca gdzie cntLeft(a + 1, n - 1) + bl + 1 <= br
        DC << " przekabacamy " << bl + 1 << " typow z prawej " << eol;
        int p = a, s, k = n - 1;

        bool xd = false;
        rep(xdd, 1, 2) if(k > a + xdd && cntLeft(l, r, a + 1 + xdd, n - 1) + bl + 1 <= br) { k = a + xdd; xd = true; break; }

        while(k - p > 1) {
            s = (p + k) / 2;
            if(cntLeft(l, r, s + 1, n - 1) + bl + 1 <= br) k = s;
            else p = s;
        }
        return {k, max(k + 1, r)};
    }
    return {0, 0};
}

void calcTree() {
    DC << "Builbimg tree" << eol;
    treeBase = 1 << (32 - __builtin_clz(m));
    rep(i, 0, m) t[i + treeBase] = { {{0, arr[i] - 1}, arr[i] + 1}, {{arr[i], n}, arr[i]}};
    rep(i, m, treeBase) t[i + treeBase] = { {{0, n}, 0} };
    repD(i, treeBase - 1, 0) {
        vector<pair<pair<int, int>, int>> treatSeparately;
        repIn2(lr, add, t[i * 2]) {
            auto [l, r] = lr;
            auto nl = (l + add) % (n + 1), nr = (r + add) % (n + 1);
            if(nl > nr) { treatSeparately.pb({{l, ((n - add) % (n + 1) + n + 1) % (n + 1)}, add}); treatSeparately.pb({{((-add) % (n + 1) + n + 1) % (n + 1), r}, add}); continue; }
            auto it = ranges::upper_bound(t[2 * i + 1], make_pair(make_pair(nr, (int)1e9), (int)1e9));
            if(it == t[2 * i + 1].begin()) it = t[2 * i + 1].end();
            auto start = it;
            do {
                it--;
                auto [l2, r2] = it -> first;
                if(r2 < nl || nr < l2) break;
                t[i].pb(make_pair(make_pair(((max(l2, nl) - add) % (n + 1) + n + 1) % (n + 1), ((min(nr, r2) - add) % (n + 1) + n + 1) % (n + 1)), (add + it -> second) % (n + 1)));
                if(it == t[2 * i + 1].begin()) it = t[2 * i + 1].end();
            } while(it != start);
        }
        repIn2(lr, add, treatSeparately) {
            auto [l, r] = lr;
            auto nl = (l + add) % (n + 1), nr = (r + add) % (n + 1);
            if(nl > nr) { treatSeparately.pb({{l, ((n - add) % (n + 1) + n + 1) % (n + 1)}, add}); treatSeparately.pb({{((-add) % (n + 1) + n + 1) % (n + 1), r}, add}); continue; }
            auto it = ranges::upper_bound(t[2 * i + 1], make_pair(make_pair(nr, (int)1e9), (int)1e9));
            if(it == t[2 * i + 1].begin()) it = t[2 * i + 1].end();
            auto start = it;
            do {
                it--;
                auto [l2, r2] = it -> first;
                if(r2 < nl || nr < l2) break;
                t[i].pb(make_pair(make_pair(((max(l2, nl) - add) % (n + 1) + n + 1) % (n + 1), ((min(nr, r2) - add) % (n + 1) + n + 1) % (n + 1)), (add + it -> second) % (n + 1)));
                if(it == t[2 * i + 1].begin()) it = t[2 * i + 1].end();
            } while(it != start);
        }
        ranges::stable_sort(t[i]);
    }
    DEBUG {
        DC << "Tree built        /\\" << eol << eol;
    }
}

vector<int> basesL, basesR;
int queryTree(int l, int r, int startState) {
    DC << "Q " << l << ' ' << r << "  startState " << startState << eol;
    l += treeBase;
    r += treeBase;
    basesL.clear(); basesR.clear();
    basesL.pb(l);
    if(l != r) basesR.pb(r);
    while(l / 2 != r / 2) {
        if(l % 2 == 0) basesL.pb(l + 1);
        if(r % 2 == 1) basesR.pb(r - 1);
        l /= 2;
        r /= 2;
    }
    repIn(i, basesL) {
        auto it = ranges::upper_bound(t[i], make_pair(make_pair(startState, (int)1e9), (int)1e9));
        if(it == t[i].begin()) it = t[i].end();
        it--;
        DC << (it -> first.first) << ' ' << (it -> first.second) << "  adds " << (it -> second) << " -> (" << startState << " + " << (it -> second) << ") % " << n + 1 << " = ";
        startState = (startState + it -> second) % (n + 1);
        DC << startState << eol;
    }
    ranges::reverse(basesR);
    repIn(i, basesR) {
        auto it = ranges::upper_bound(t[i], make_pair(make_pair(startState, (int)1e9), (int)1e9));
        if(it == t[i].begin()) it = t[i].end();
        it--;
        DC << (it -> first.first) << ' ' << (it -> first.second) << "  adds " << (it -> second) << " -> (" << startState << " + " << (it -> second) << ") % " << n + 1 << " = ";
        startState = (startState + it -> second) % (n + 1);
        DC << startState << eol;
    }
    return startState;
}

int binsearch(int start, int end, int l, int r) {
    // szukamy ostatniego miejsca gdzie maxH1 <= l && minH2 >= r oraz sie nie spotkaja
    int p = start - 1, s, k = end;
    while(k - p > 1) {
        s = (p + k) / 2;
        ll sumH1 = prefSumH1[s + 1] - prefSumH1[start];
        ll sumH2 = prefSumH2[s + 1] - prefSumH2[start];
        if(getMaxH1(start, s) > l || getMinH2(start, s) < r || l + sumH1 >= r - sumH2 || cntLeft(l, r, l + 1, (l + r) / 2) < sumH1 || cntRight(l, r, (l + r) / 2 + 1, r) < sumH2) k = s;
        else p = s;
    }
    return p;
}

int main() {
    initBuffer();
    getInt(n); getInt(m);
    char c;
    while((buffer[bufI] != 'R' && buffer[bufI] != 'B') && (buffer[bufI] != '>' && buffer[bufI] != '<')) bufI++;
    rep(i, 0, n) c = buffer[bufI++], ogRight[i] = (c == 'R') || (c == '>');
    rep(i, 0, n) prefSum[i + 1] = prefSum[i] + ogRight[i];

    rep(i, 0, m) getInt(arr[i]);
    int h1Cutoff = n / 2;
    rep(i, 0, m) {
        prefSumH1[i + 1] = prefSumH1[i];
        prefSumH2[i + 1] = prefSumH2[i];
        if(arr[i] <= h1Cutoff) {
            prefSumH1[i + 1] += arr[i];
            maxH1[i][0] = arr[i] - 1;
            minH2[i][0] = inf;
        }
        else { 
            prefSumH2[i + 1] += n - arr[i];
            minH2[i][0] = arr[i] - 1;
            maxH1[i][0] = -inf;
        }
    }
    rep(k, 1, maxLog) rep(i, 0, m) maxH1[i][k] = max(maxH1[i][k - 1], maxH1[min(m - 1, i + (1 << (k - 1)))][k - 1]);
    rep(k, 1, maxLog) rep(i, 0, m) minH2[i][k] = min(minH2[i][k - 1], minH2[min(m - 1, i + (1 << (k - 1)))][k - 1]);
    calcTree();

    string output, str;

    pair<int, int> lrIni = {-1, n};
    while(lrIni.first < n && ogRight[lrIni.first + 1]) lrIni.first++;
    while(lrIni.second && !ogRight[lrIni.second - 1]) lrIni.second--;

    int q;
    getInt(q);
    rep(i, 0, q) {
        int start, end;
        getInt(start); getInt(end);
        start--; end--;
        auto [l, r] = lrIni;
        bool lastFound = false;
        while(start <= end) {
            if(l + 1 == r) {
                DC << "Spotkali sie" << eol;
                break;
            }

            int p = start - 1;
            if(!lastFound) {
                int s = start;
                ll sumH1 = prefSumH1[s + 1] - prefSumH1[start];
                ll sumH2 = prefSumH2[s + 1] - prefSumH2[start];
                if(!(getMaxH1(start, s) > l || getMinH2(start, s) < r || l + sumH1 >= r - sumH2 || cntLeft(l, r, l + 1, (l + r) / 2) < sumH1 || cntRight(l, r, (l + r) / 2 + 1, r) < sumH2)) p = binsearch(start, end, l, r);
            }
            DC << "Z lr " << l << ' ' << r << "  przedzial krasnoludkow " << start << ' ' << end << " binsearch wyplul " << p << eol;
            if(p == start - 1) {
                auto lr = f(l, r, arr[start] - 1);
                l = lr.first; r = lr.second;
                lastFound = false;
            }
            else {
                lastFound = true;
                // szukamy pierwszego miejsca gdzie cntLeft(l + 1, x) >= sumH1(start, p)
                ll sumH1 = prefSumH1[p + 1] - prefSumH1[start];
                int pp = l - 1, ss, kk = r - 1;
                while(kk - pp > 1) {
                    ss = (pp + kk) / 2;
                    if(max(0, cntLeft(l, r, l + 1, ss)) >= sumH1) kk = ss;
                    else pp = ss;
                }
                l = kk;

                // szukamy ostatniego miejsca gdzie cntRight(x, r - 1) >= sumH2(start, p)
                ll sumH2 = prefSumH2[p + 1] - prefSumH2[start];
                pp = 0, kk = r + 1;
                while(kk - pp > 1) {
                    ss = (pp + kk) / 2;
                    if(max(0, cntRight(l, r, ss, r - 1)) >= sumH2) pp = ss;
                    else kk = ss;
                }
                r = pp;

                if(l >= r) l = r - 1;

                start = p;
            }

            DC << "Nowe lr: " << l << ' ' << r << eol;
            start++;
        }
        int ans = (start <= end) ? queryTree(start, end, l + 1) : cntRight(l, r, 0, n - 1);
        str.clear();
        while(ans) str += (char)(ans % 10 + '0'), ans /= 10;
        if(str.empty()) str = '0';
        ranges::reverse(str);
        str.pb('\n');
        output += str;
    }

    fwrite_unlocked(output.c_str(), sizeof(char), output.size(), stdout);

}

Compilation message (stderr)

Main.cpp: In function 'void initBuffer()':
Main.cpp:32:19: warning: ignoring return value of 'size_t fread_unlocked(void*, size_t, size_t, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
   32 |     fread_unlocked(buffer, sizeof(char), bufSize, stdin);
      |     ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#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...