Submission #1192939

#TimeUsernameProblemLanguageResultExecution timeMemory
1192939phawinbotNaval battle (CEOI24_battle)C++20
100 / 100
1179 ms97668 KiB
// Naval Battle
// CEOI 2024 Day 1
// 100 points submission

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
using P = pair<int, int>;

#define x first
#define y second

int n;
P pos[202020];
char d[202020];

const int NEVER = 1999999999 + 7;

bool gone[202020];


vector<set<P>> enemyCollection;

int getNewSet() {
    int z = enemyCollection.size();
    enemyCollection.push_back(set<P>());
    return z;
}

int crashCheckLow(int pos, int sid) {
    // fprintf(stderr, "  Opponent Set: %d\n", sid);
    while(!enemyCollection[sid].empty()) {
        auto it = enemyCollection[sid].lower_bound({pos, -1});
        if(it == enemyCollection[sid].begin()) return NEVER;
        it--;
        int idx = (*it).second;
        if(gone[idx]) {
            enemyCollection[sid].erase(it);
        } else {
            return pos - (*it).first;
        }
    }
    return NEVER;
}

int crashCheckHigh(int pos, int sid) {
    // fprintf(stderr, "  Opponent Set: %d\n", sid);
    while(!enemyCollection[sid].empty()) {
        auto it = enemyCollection[sid].upper_bound({pos, 303030});
        if(it == enemyCollection[sid].end()) return NEVER;
        int idx = (*it).second;
        if(gone[idx]) {
            enemyCollection[sid].erase(it);
        } else {
            return (*it).first - pos;
        }
    }
    return NEVER;
}

class OpponentInfo {
public:
    int myPos;
    char myTeam;
    int sid;

    OpponentInfo() {}
};



vector<OpponentInfo> opponents[202020];

int getCrashTime(int idx) {
    int earliest = NEVER;
    for(OpponentInfo O: opponents[idx]) {
        // fprintf(stderr, "Check Crash Time of ship %d\n", idx + 1);
        int thisRound = NEVER;
        if(O.myTeam == 'L') {
            thisRound = crashCheckHigh(O.myPos, O.sid);
        } else {
            thisRound = crashCheckLow(O.myPos, O.sid);
        }
        earliest = min(earliest, thisRound);
    }
    return earliest;
}

priority_queue<P> ICU;
int nextEvent[202020];



void preProcessSUM(const vector<P> &ships) {
    if(ships.size() <= 1) return;
    const int NORTH_SET = getNewSet();
    const int SOUTH_SET = getNewSet();
    const int WEST_SET = getNewSet();
    const int EAST_SET = getNewSet();

    int z = ships.size();
    for(int i = 0; i < z; i++) {
        int idx = ships[i].second;
        int pos = ships[i].first;
        OpponentInfo info;
        info.myPos = pos;
        if(d[idx] == 'N') {
            enemyCollection[NORTH_SET].insert({pos, idx});
            info.sid = WEST_SET;
            info.myTeam = 'L';
        } else if(d[idx] == 'W') {
            enemyCollection[WEST_SET].insert({pos, idx});
            info.sid = NORTH_SET;
            info.myTeam = 'R';
            ////
        } else if(d[idx] == 'S') {
            enemyCollection[SOUTH_SET].insert({pos, idx});
            info.sid = EAST_SET;
            info.myTeam = 'R';
        } else if(d[idx] == 'E') {
            enemyCollection[EAST_SET].insert({pos, idx});
            info.sid = SOUTH_SET;
            info.myTeam = 'L';
        }

        opponents[idx].push_back(info); 
    }
}

void preProcessDIFF(const vector<P> &ships) {
    if(ships.size() <= 1) return;
    const int NORTH_SET = getNewSet();
    const int SOUTH_SET = getNewSet();
    const int WEST_SET = getNewSet();
    const int EAST_SET = getNewSet();

    int z = ships.size();
    // fprintf(stderr, "%d ships to consider\n", z);
    for(int i = 0; i < z; i++) {
        int idx = ships[i].second;
        int pos = ships[i].first;
        OpponentInfo info;
        info.myPos = pos;
        if(d[idx] == 'N') {
            enemyCollection[NORTH_SET].insert({pos, idx});
            info.sid = EAST_SET;
            info.myTeam = 'R';
        } else if(d[idx] == 'E') {
            enemyCollection[EAST_SET].insert({pos, idx});
            info.sid = NORTH_SET;
            info.myTeam = 'L';
            ////
        } else if(d[idx] == 'W') {
            enemyCollection[WEST_SET].insert({pos, idx});
            info.sid = SOUTH_SET;
            info.myTeam = 'R';
        } else if(d[idx] == 'S') {
            enemyCollection[SOUTH_SET].insert({pos, idx});
            info.sid = WEST_SET;
            info.myTeam = 'L';
        }

        opponents[idx].push_back(info); 
    }
}

void preProcessLine(const vector<P> &ships) {
    if(ships.size() <= 1) return;
    const int LOW_SET = getNewSet();
    const int HIGH_SET = getNewSet();

    int z = ships.size();
    // fprintf(stderr, "%d ships to consider\n", z);
    for(int i = 0; i < z; i++) {
        int idx = ships[i].second;
        int pos = ships[i].first;
        // fprintf(stderr, "(Ship %d, Pos = %d)\n", idx + 1, pos);
        OpponentInfo info;
        info.myPos = pos / 2;
        
        if(d[idx] == 'S' || d[idx] == 'E') {
            // increase coordinate by 1 (team LOW)
            enemyCollection[LOW_SET].insert({pos / 2, idx});
            info.myTeam = 'L';
            info.sid = HIGH_SET;
        } else if(d[idx] == 'N' || d[idx] == 'W') {
            // decrease coordinate by 1 (team HIGH)
            enemyCollection[HIGH_SET].insert({pos / 2, idx});
            info.myTeam = 'R';
            info.sid = LOW_SET;
        }

        opponents[idx].push_back(info);
    }
}


void processEvent(const int t) {
    // {{ Event on top of ICU is actually going to happen at time t }}
    set<int> eliminated;

    while(!ICU.empty()) {
        int claim = -ICU.top().first;
        int idx = ICU.top().second;
        if(claim != t) break;

        ICU.pop();

        int actual = getCrashTime(idx);
        if(actual == t) {
            // Yes!
            eliminated.insert(idx);
        } else {
            if(actual < NEVER) {
                ICU.push({-actual, idx});
            }
        }
    }

    for(int u: eliminated) gone[u] = true;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n;
    for(int i = 0; i < n; i++) {
        cin >> pos[i].x >> pos[i].y;
        string s; cin >> s;
        d[i] = s[0];

        // fprintf(stderr, "Registered Ship %d at (%d, %d) [%c]\n", i + 1, pos[i].x, pos[i].y, d[i]);
    }


    // Prepare Initial Crash
    map<int, vector<P>> sumBank, diffBank, xBank, yBank;
    for(int i = 0; i < n; i++) {
        sumBank[pos[i].x + pos[i].y].push_back({pos[i].x, i});
        diffBank[pos[i].x - pos[i].y].push_back({pos[i].x, i});
        if(d[i] == 'N' || d[i] == 'S') xBank[pos[i].x].push_back({pos[i].y, i});
        if(d[i] == 'E' || d[i] == 'W') yBank[pos[i].y].push_back({pos[i].x, i});
    }

    for(auto it = sumBank.begin(); it != sumBank.end(); it++) preProcessSUM(it->second);
    for(auto it = diffBank.begin(); it != diffBank.end(); it++) preProcessDIFF(it->second);
    for(auto it = xBank.begin(); it != xBank.end(); it++) preProcessLine(it->second);
    for(auto it = yBank.begin(); it != yBank.end(); it++) preProcessLine(it->second);


    // Start the Battle
    for(int i = 0; i < n; i++) {
        nextEvent[i] = getCrashTime(i);
        if(nextEvent[i] < NEVER) {
            ICU.push({-nextEvent[i], i});
        }
        // fprintf(stderr, "Preliminary[Ship %d]: crash at t = %d\n", i + 1, nextEvent[i]);
    }

    while(!ICU.empty()) {
        int claim = -ICU.top().first;
        int idx = ICU.top().second;
        
        // Re-Evaluation
        int actual = getCrashTime(idx);
        if(actual == claim) {
            processEvent(actual);
        } else {
            ICU.pop();
            if(actual < NEVER) {
                ICU.push({-actual, idx});
            }
        }

    }

    // Final Answer
    for(int i = 0; i < n; i++) if(!gone[i]) cout << (i + 1) << "\n";
    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...
#Verdict Execution timeMemoryGrader output
Fetching results...