Submission #1249333

#TimeUsernameProblemLanguageResultExecution timeMemory
12493331ncogn1toDragon 2 (JOI17_dragon2)C++20
100 / 100
544 ms11844 KiB
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <deque>
#include <string>
#include <string.h>
#include <vector>
#include <set>
#include <map>
#include <stdlib.h>
#include <complex>
using namespace std;

// maksymalna liczba smoków, zapytań, bitów do fenwick (BS -> 2^15=32768)
const int MN = 30000, MQ = 100000, BS = 15, RQ = 300;

typedef complex<long long> point;  // punkt jako liczba zespolona (x + yi)

// Funkcja obliczająca orientację (2D cross product) P1 x P2
long long op(point P1, point P2) {
    // conj(P1)*P2 daje (x1 - y1 i)*(x2 + y2 i) = ..., wyciągamy część uroj.
    return imag(conj(P1) * P2);
}

namespace std {
    // Nadpisujemy operator < dla punktów, tak aby sortować je według kąta
    bool operator<(point P1, point P2) {
        // P1 < P2 jeśli P1 leży bardziej "w lewo" niż P2, czyli op(P1,P2)>0
        return op(P1, P2) > 0;
    }
}

// Fenwick Tree (Binary Indexed Tree) na sumy typu T
template<class T>
class sumBIT {
private:
    T *bit;
    int S;
public:
    sumBIT(int S0) {
        S = S0;
        // alokacja tablicy size = 2^S
        bit = (T *)calloc(sizeof(T), 1 << S);
    }
    
    // dodaj k do pozycji i
    void add(int i, T k) {
        int p = i + 1;
        while (p < (1 << S)) {
            bit[p] += k;
            p += p & -p;
        }
    }
    
    // sum prefix sum od 1 do p
    T sum(int p) {
        T ret = 0;
        while (p > 0) {
            ret += bit[p];
            p -= p & -p;
        }
        return ret;
    }
    
    // suma w przedziale [a, b)
    T rag(int a, int b) {
        return sum(b) - sum(a);
    }
};

int main() {
    int n, m;
    // n = liczba smoków, m = liczba plemion
    scanf("%d%d", &n, &m);
    
    static point P[MN];   // pozycje smoków
    static int C[MN];     // przynależność plemienna (0-index)
    for (int i = 0; i < n; i++) {
        long long x, y;
        scanf("%lld%lld%d", &x, &y, C + i);
        P[i] = point(x, y);
        C[i]--;  // odjęcie 1 dla 0-based
    }
    
    // Wczytanie wiosek
    long long d1, e1, d2, e2;
    scanf("%lld%lld%lld%lld", &d1, &e1, &d2, &e2);
    point X = point(d1, e1), Y = point(d2, e2);

    // F[i] = true jeśli P[i] leży po lewej stronie wektora X->Y
    static bool F[MN];
    for (int i = 0; i < n; i++) {
        F[i] = (op(Y - X, P[i] - X) > 0);
    }

    // A[i] = wektor od Y do P[i] (jeśli F[i]) lub od P[i] do Y
    static point A[MN];
    // AA = pary (plemię, wektor) do sortowania globalnego
    static pair<int, point> AA[MN];
    for (int i = 0; i < n; i++) {
        A[i] = (F[i] ? P[i] - Y : Y - P[i]);
        AA[i] = make_pair(C[i], A[i]);
    }
    // Sortujemy wszystkie pary po plemieniu, a w ramach plemienia po kącie
    sort(AA, AA + n);

    // D[i] = indeks pary (C[i], A[i]) w posortowanym AA
    static int D[MN];
    for (int i = 0; i < n; i++) {
        D[i] = lower_bound(AA, AA + n, make_pair(C[i], A[i])) - AA;
    }

    // T[k] = początek przedziału dla plemienia k (w AA)
    static int T[MN + 1];
    for (int i = 0; i <= m; i++) {
        // szukamy pierwszego elementu >= (i, dowolny wektor jak Y-X)
        T[i] = lower_bound(AA, AA + n, make_pair(i, Y - X)) - AA;
    }

    // Pr = wektory od X do P[i] (lub odwrotnie), wraz z indeksem i, posortowane rosnąco
    static pair<point, int> Pr[MN];
    for (int i = 0; i < n; i++) {
        Pr[i] = make_pair(F[i] ? P[i] - X : X - P[i], i);
    }
    sort(Pr, Pr + n);

    int Q;
    scanf("%d", &Q);
    static int as[MQ], bs[MQ];   // zapytania: as[j] atakuje bs[j]
    for (int i = 0; i < Q; i++) {
        scanf("%d%d", as + i, bs + i);
        as[i]--;
        bs[i]--;
    }

    // V[a] = lista plemion b, które a atakuje (dla "małych" plemion)
    static vector<int> V[MN], VN[MN];
    for (int i = 0; i < Q; i++) {
        V[as[i]].push_back(bs[i]);
        VN[as[i]].push_back(i);  // numer zapytania
    }
    // V2[b] = lista plemion a ("dużych"), które atakują b (odwrócenie fazy II)
    static vector<int> V2[MN], VN2[MN];
    for (int i = 0; i < Q; i++) {
        if (V[as[i]].size() >= RQ) {
            // jeśli a jest duże, przerzucamy do V2 b
            V2[bs[i]].push_back(as[i]);
            VN2[bs[i]].push_back(i);
        }
    }

    static long long ans[MQ] = {0};  // odpowiedzi

    // --- Faza I: małe plemiona ---
    sumBIT<int> seg0(BS), seg1(BS);
    // Na początku wstawiamy do seg1 wszystkie smoki po prawej
    for (int i = 0; i < n; i++) {
        if (!F[i]) seg1.add(D[i], 1);
    }
    // Sweep po kątowej kolejności względem X
    for (int t = 0; t < n; t++) {
        int i = Pr[t].second;
        int a = C[i];
        if (F[i]) {
            // gdy smok jest po lewej, obsługujemy małe zapytania z V[a]
            if (V[a].size() < RQ) {
                for (int k = 0; k < (int)V[a].size(); k++) {
                    int b = V[a][k], l = VN[a][k];
                    int L = lower_bound(AA, AA + n, make_pair(b, A[i])) - AA;
                    // dodajemy liczbę smoków plemienia b, które były już po lewej (seg0) lub po prawej (seg1)
                    ans[l] += seg0.rag(L, T[b+1]) + seg1.rag(T[b], L);
                }
            }
            seg0.add(D[i], 1);  // przenosimy tego smoka do seg0
        } else {
            // analogicznie, gdy smok po prawej
            if (V[a].size() < RQ) {
                for (int k = 0; k < (int)V[a].size(); k++) {
                    int b = V[a][k], l = VN[a][k];
                    int L = lower_bound(AA, AA + n, make_pair(b, A[i])) - AA;
                    ans[l] += seg0.rag(L, T[b+1]) + seg1.rag(T[b], L);
                }
            }
            seg1.add(D[i], -1);  // usuwamy smoka z prawej
        }
    }

    // --- Faza II: duże plemiona ---
    sumBIT<int> seg2(BS), seg3(BS);
    // seg2 trzyma wszystkie smoki jeszcze nieprzetworzone
    for (int i = 0; i < n; i++) {
        seg2.add(D[i], 1);
    }
    for (int t = 0; t < n; t++) {
        int i = Pr[t].second;
        int b = C[i];
        if (F[i]) {
            // dla każdego dużego a atakującego b
            for (int k = 0; k < (int)V2[b].size(); k++) {
                int a = V2[b][k], l = VN2[b][k];
                int L = lower_bound(AA, AA + n, make_pair(a, A[i])) - AA;
                ans[l] += seg2.rag(T[a], L);
            }
            seg2.add(D[i], -1);
            seg3.add(D[i], 1);
        } else {
            for (int k = 0; k < (int)V2[b].size(); k++) {
                int a = V2[b][k], l = VN2[b][k];
                int L = lower_bound(AA, AA + n, make_pair(a, A[i])) - AA;
                ans[l] += seg3.rag(L, T[a+1]);
            }
            seg2.add(D[i], -1);
            seg3.add(D[i], 1);
        }
    }

    // Wypisanie wyników
    for (int t = 0; t < Q; t++) {
        printf("%lld\n", ans[t]);
    }
    return 0;
}

Compilation message (stderr)

dragon2.cpp: In function 'int main()':
dragon2.cpp:75:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
   75 |     scanf("%d%d", &n, &m);
      |     ~~~~~^~~~~~~~~~~~~~~~
dragon2.cpp:81:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
   81 |         scanf("%lld%lld%d", &x, &y, C + i);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dragon2.cpp:88:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
   88 |     scanf("%lld%lld%lld%lld", &d1, &e1, &d2, &e2);
      |     ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dragon2.cpp:129:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  129 |     scanf("%d", &Q);
      |     ~~~~~^~~~~~~~~~
dragon2.cpp:132:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  132 |         scanf("%d%d", as + i, bs + i);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...