답안 #594976

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
594976 2022-07-13T08:18:50 Z 박상훈(#8436) Dragon 2 (JOI17_dragon2) C++17
60 / 100
4000 ms 40452 KB
#include <bits/stdc++.h>

typedef long long ll;
using namespace std;
struct Query{
    int c, d, i;
    bool inv;
    bool operator<(const Query &Q) const{
        if (d==Q.d) return c<Q.c;
        return d<Q.d;
    }
}Q[100100];
ll ans[100100], it = 0;

struct Point;
ll xo, yo;
int ccw(Point a, Point b, Point c);

struct Point{
    ll x, y, i;
    Point(){}
    Point(ll _x, ll _y, ll _i): x(_x), y(_y), i(_i) {}

    bool operator<(const Point &P) const{
        bool left1 = (x-xo<0 || (x-xo==0 && y-yo>0));
        bool left2 = (P.x-xo<0 || (P.x-xo==0 && P.y-yo>0));
        if (left1!=left2) return left1 > left2;

        return ccw(Point(xo, yo, 0), *this, P) > 0;
    }
}a[60060], b[60060], O1, O2;
int n, ccol, c[30030], nx[30030], ny[30030], opa[30030], opb[30030];
vector<int> T[30030];

int ccw(Point a, Point b, Point c){
    ll ret = (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
    if (ret>0) return 1;
    if (ret<0) return -1;
    return 0;
}

struct Seg{
    vector<int> a, tree;
    int sz;
    void init(){
        sz = a.size();
        tree.resize(sz*2, 0);
    }
    int getidx(int y){
        return lower_bound(a.begin(), a.end(), y) - a.begin();
    }
    void update(int y, int val){
        y = getidx(y) + sz;
        for (tree[y]+=val;y>1;y>>=1) tree[y>>1] = tree[y] + tree[y^1];
    }
    int query(int l, int r){
        int ret = 0;
        l = getidx(l), r = getidx(r+1);
        for (l+=sz, r+=sz;l<r;l>>=1, r>>=1){
            if (l&1) ret += tree[l++];
            if (r&1) ret += tree[--r];
        }
        return ret;
    }
};
struct Seg2D{
    Seg tree[120120];
    int sz;
    void init(int N){
        sz = N;
        for (int i=sz+1;i<sz*2;i++){
            if (i-sz<=n){
                tree[i].a.push_back(ny[a[i-sz].i]);
                tree[i].a.push_back(ny[a[i-sz].i]+n);
            }
            else{
                tree[i].a.push_back(ny[a[i-sz-n].i]);
                tree[i].a.push_back(ny[a[i-sz-n].i]+n);
            }
        }
        for (int i=sz-1;i;i--){
            tree[i].a.resize(tree[i<<1].a.size() + tree[i<<1|1].a.size());
            merge(tree[i<<1].a.begin(), tree[i<<1].a.end(), tree[i<<1|1].a.begin(), tree[i<<1|1].a.end(), tree[i].a.begin());
        }

        for (int i=1;i<sz*2;i++) tree[i].init();
    }
    void update(int x, int y, int val){
        //return;
        for (x+=sz;x;x>>=1){
            tree[x].update(y, val);
        }
    }
    int query(int x1, int x2, int y1, int y2){
        //return 0;
        x2++;
        int ret = 0;
        for (x1+=sz, x2+=sz;x1<x2;x1>>=1, x2>>=1){
            if (x1&1) ret += tree[x1++].query(y1, y2);
            if (x2&1) ret += tree[--x2].query(y1, y2);
        }
        return ret;
    }
}tree;

void update(int x, int y, int val){
    //printf(" %d %d %d\n", x, y, val);
    tree.update(x, y, val);
    tree.update(x, y+n, val);
    tree.update(x+n, y, val);
    tree.update(x+n, y+n, val);
}

ll query(int x1, int x2, int y1, int y2){
    int c1 = ccol;
    ll ret = 0;
    for (int i=x1;i<=x2;i++){
        if (y1 <= ny[a[i].i] && ny[a[i].i] <= y2 && c[a[i].i]==c1) ret++;
        if (y1 <= ny[a[i].i]+n && ny[a[i].i]+n <= y2 && c[a[i].i]==c1) ret++;
    }
    return ret;
}

pair<int, int> get_range(Point a[], int op[], int sx, bool v, Point Z2, Point Z3){
    if (op[sx]==sx+n){
        if ((ccw(Z2, a[sx], Z3)==1) != v) return {sx+1, sx+n-1};
        return {sx+1, sx};
    }
    if ((ccw(Z2, a[sx], Z3)==ccw(Z2, a[sx], a[op[sx]])) == v) return {sx+1, op[sx]-1};
    return {op[sx], sx+n-1};
    /*
    int qx1, qx2;

    int sx = lx-1, px = rx+1;
    bool flagL = (ccw(Z1, Z2, Z3)*ccw(Z1, Z2, a[lx])==v);
    while(lx<=rx){
        int mx = (lx+rx)>>1;
        bool flagm = (ccw(Z1, Z2, Z3)*ccw(Z1, Z2, a[mx])==v);
        if (flagm==flagL) lx = mx+1;
        else rx = mx-1, px = mx;
    }

    if (flagL) qx1 = sx+1, qx2 = px-1;
    else qx1 = px, qx2 = sx+n-1;

    return {qx1, qx2};*/
}

ll calc1(int c1){
    ll ret = 0;
    for (auto &i:T[c1]){
        it++;
        int sx = nx[i], sy = ny[i];
        //auto Rx = get_range(a, sx+1, sx+n-1, 1, a[sx], O1, O2);
        //auto Ry = get_range(b, sy+1, sy+n-1, 1, b[sy], O2, O1);

        auto Rx = get_range(a, opa, sx, 0, O1, O2);
        auto Ry = get_range(b, opb, sy, 0, O2, O1);

        //printf("%lld %lld -> %d, %d / %d, %d\n", a[sx].x, a[sx].y, Rx.first, Rx.second, Ry.first, Ry.second);

        /*int lx = sx+1, rx = sx+n-1, px = sx+n;
        bool flagL = (ccw(a[sx], O1, O2)==ccw(a[sx], O1, a[lx]));
        while(lx<=rx){
            int mx = (lx+rx)>>1;
            bool flagm = (ccw(a[sx], O1, O2)==ccw(a[sx], O1, a[mx]));
            if (flagm==flagL) lx = mx+1;
            else rx = mx-1, px = mx;
        }

        if (flagL) qx1 = sx+1, qx2 = px-1;
        else qx1 = px, qx2 = sx+n-1;

        int ly = sy+1, ry = sy+n-1, py = sy+n;
        flagL = (ccw(b[sy], O2, O1)==ccw(b[sy], O2, b[ly]));
        while(ly<=ry){
            int my = (ly+ry)>>1;
            bool flagm = (ccw(b[sy], O2, O1)==ccw(b[sy], O2, b[my]));
            if (flagm==flagL) ly = my+1;
            else ry = my-1, py = my;
        }

        if (flagL) qy1 = sy+1, qy2 = py-1;
        else qy1 = py, qy2 = sy+n-1;*/

        //printf("ok\n");
        ret += tree.query(Rx.first, Rx.second, Ry.first, Ry.second);

        //printf("%d %d %d %d: %d / %lld\n", qx1, qx2, qy1, qy2, tree.query(qx1, qx2, qy1, qy2), query(qx1, qx2, qy1, qy2));

        /*for (int j=sx+1;j<sx+n;j++){
            if (ccw(a[sx], O1, O2)!=ccw(a[sx], O1, a[j])) continue;
            if (ccw(b[sy], O2, O1)!=ccw(b[sy], O2, a[j])) continue;
            if (c[a[j].i]!=c2) continue;
            //printf("ok: %lld %lld %lld %lld (j = %d / %lld %lld)\n", a[sx].x, a[sx].y, a[j].x, a[j].y, j, b[sy].x, b[sy].y);
            ret++;
        }*/
    }
    return ret;
}

ll calc2(int c){
    ll ret = 0;
    for (auto &i:T[c]){
        it++;
        ///Case #1
        int sx = nx[i], sy = ny[i];
        auto Rx = get_range(a, opa, sx, 1, O1, O2);
        auto Ry = get_range(b, opb, sy, 1, O2, O1);

        ret += tree.query(Rx.first, Rx.second, Ry.first, Ry.second);


        ///Case #2
        pair<int, int> S1, S2;
        S1 = get_range(a, opa, sx, 0, O1, O2);
        S2 = get_range(b, opb, sy, 0, O2, O1);
        //printf(" org: %d %d %d %d\n", sx+1, sx+n-1, sy+1, sy+n-1);
        //printf(" R: %d %d %d %d\n", Rx.first, Rx.second, Ry.first, Ry.second);
        //printf(" S: %d %d %d %d\n", S1.first, S1.second, S2.first, S2.second);
        if (ccw(O1, O2, a[sx])==1){ /// 0 -> 1
            int tmp = nx[n];
            if (!(sx<tmp && tmp<sx+n)) tmp += n;
            assert(sx<tmp && tmp<sx+n);
            S1.second = tmp-1;
        }
        else{ /// 1 -> 0
            int tmp = nx[n];
            if (!(sx<tmp && tmp<sx+n)) tmp += n;
            assert(sx<tmp && tmp<sx+n);
            S1.first = tmp+1;
        }

        if (ccw(O2, O1, a[sx])==1){ ///0 -> 1
            int tmp = ny[n];
            if (!(sy<tmp && tmp<sy+n)) tmp += n;
            assert(sy<tmp && tmp<sy+n);
            S2.second = tmp-1;
        }
        else{ /// 1 -> 0
            int tmp = ny[n];
            if (!(sy<tmp && tmp<sy+n)) tmp += n;
            assert(sy<tmp && tmp<sy+n);
            S2.first = tmp+1;
        }

        ret += tree.query(S1.first, S1.second, S2.first, S2.second);

        //printf(" %lld %lld -> %d + %d\n", a[sx].x, a[sx].y, tree.query(Rx.first, Rx.second, Ry.first, Ry.second), tree.query(S1.first, S1.second, S2.first, S2.second));
        //printf(" S: %d %d %d %d\n\n", S1.first, S1.second, S2.first, S2.second);
    }
    return ret;
}

void init(Point O, Point a[], int nx[], int op[]){
    xo = O.x, yo = O.y;
    sort(a+1, a+n+1);
    for (int i=n+1;i<=n*2;i++) a[i] = a[i-n];

    for (int i=1;i<=n;i++) nx[a[i].i] = i;

    int pt = 2;
    for (int i=1;i<=n;i++){
        while(pt<i+n && ccw(O, a[i], a[pt]) >= 0) pt++;
        op[i] = pt;
        //printf("%lld %lld -> %lld %lld (%d)\n",  a[i].x, a[i].y, a[op[i]].x, a[op[i]].y, ccw(O, a[i], a[pt]));
    }
    //printf("\n");
}

int main(){
    //freopen("Big.txt", "r", stdin);
    int m;
    scanf("%d %d", &n, &m);
    for (int i=1;i<=n;i++){
        scanf("%lld %lld %d", &a[i].x, &a[i].y, c+i);
        a[i].i = i;
        b[i] = a[i];
        T[c[i]].push_back(i);
    }

    scanf("%lld %lld %lld %lld", &O1.x, &O1.y, &O2.x, &O2.y);
    a[n+1] = O2, b[n+1] = O1;
    a[n+1].i = n+1, b[n+1].i = n+1;
    ++n;
    init(O1, a, nx, opa);
    init(O2, b, ny, opb);

    tree.init(n*2+1);

    int q;
    scanf("%d", &q);
    for (int i=1;i<=q;i++){
        scanf("%d %d", &Q[i].c, &Q[i].d);
        Q[i].i = i;

        if (T[Q[i].c].size() > T[Q[i].d].size()){
            Q[i].inv = 1;
            swap(Q[i].c, Q[i].d);
        }
        else if (T[Q[i].c].size()==T[Q[i].d].size() && Q[i].c > Q[i].d){
            Q[i].inv = 1;
            swap(Q[i].c, Q[i].d);
        }
        else Q[i].inv = 0;
    }

    sort(Q+1, Q+q+1);
    ccol = 0;
    for (int i=1;i<=q;i++){
        //if (i%10000==0) printf("ok %d queries\n", i);
        //printf("YES %d\n", i);
        if (ccol!=Q[i].d){
            for (auto &j:T[ccol]) update(nx[j], ny[j], -1);
            for (auto &j:T[Q[i].d]) update(nx[j], ny[j], 1);
            ccol = Q[i].d;
        }

        //printf("update ok\n");
        if (i>1 && Q[i].c==Q[i-1].c && Q[i].d==Q[i-1].d && Q[i].inv==Q[i-1].inv){
            ans[Q[i].i] = ans[Q[i-1].i];
            continue;
        }

        if (!Q[i].inv) ans[Q[i].i] = calc1(Q[i].c);
        else ans[Q[i].i] = calc2(Q[i].c);
    }

    //printf("Total iterations: %lld\n", it);
    for (int i=1;i<=q;i++) printf("%lld\n", ans[i]);
    return 0;
}

Compilation message

dragon2.cpp: In function 'int main()':
dragon2.cpp:274:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  274 |     scanf("%d %d", &n, &m);
      |     ~~~~~^~~~~~~~~~~~~~~~~
dragon2.cpp:276:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  276 |         scanf("%lld %lld %d", &a[i].x, &a[i].y, c+i);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dragon2.cpp:282:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  282 |     scanf("%lld %lld %lld %lld", &O1.x, &O1.y, &O2.x, &O2.y);
      |     ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dragon2.cpp:292:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  292 |     scanf("%d", &q);
      |     ~~~~~^~~~~~~~~~
dragon2.cpp:294:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  294 |         scanf("%d %d", &Q[i].c, &Q[i].d);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
# 결과 실행 시간 메모리 Grader output
1 Correct 17 ms 10324 KB Output is correct
2 Correct 42 ms 10324 KB Output is correct
3 Correct 265 ms 10544 KB Output is correct
4 Correct 263 ms 13644 KB Output is correct
5 Correct 125 ms 13804 KB Output is correct
6 Correct 19 ms 10428 KB Output is correct
7 Correct 21 ms 10524 KB Output is correct
8 Correct 18 ms 10400 KB Output is correct
9 Correct 15 ms 10376 KB Output is correct
10 Correct 13 ms 10380 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 292 ms 39916 KB Output is correct
2 Correct 1106 ms 39952 KB Output is correct
3 Correct 592 ms 40024 KB Output is correct
4 Correct 132 ms 39940 KB Output is correct
5 Correct 60 ms 40452 KB Output is correct
6 Correct 265 ms 40016 KB Output is correct
7 Correct 207 ms 39924 KB Output is correct
8 Correct 242 ms 39912 KB Output is correct
9 Correct 131 ms 39872 KB Output is correct
10 Correct 151 ms 39740 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 17 ms 10324 KB Output is correct
2 Correct 42 ms 10324 KB Output is correct
3 Correct 265 ms 10544 KB Output is correct
4 Correct 263 ms 13644 KB Output is correct
5 Correct 125 ms 13804 KB Output is correct
6 Correct 19 ms 10428 KB Output is correct
7 Correct 21 ms 10524 KB Output is correct
8 Correct 18 ms 10400 KB Output is correct
9 Correct 15 ms 10376 KB Output is correct
10 Correct 13 ms 10380 KB Output is correct
11 Correct 292 ms 39916 KB Output is correct
12 Correct 1106 ms 39952 KB Output is correct
13 Correct 592 ms 40024 KB Output is correct
14 Correct 132 ms 39940 KB Output is correct
15 Correct 60 ms 40452 KB Output is correct
16 Correct 265 ms 40016 KB Output is correct
17 Correct 207 ms 39924 KB Output is correct
18 Correct 242 ms 39912 KB Output is correct
19 Correct 131 ms 39872 KB Output is correct
20 Correct 151 ms 39740 KB Output is correct
21 Correct 268 ms 39884 KB Output is correct
22 Correct 995 ms 39968 KB Output is correct
23 Execution timed out 4035 ms 40172 KB Time limit exceeded
24 Halted 0 ms 0 KB -