Submission #1077975

#TimeUsernameProblemLanguageResultExecution timeMemory
1077975azberjibiouCard Collection (JOI24_collection)C++17
100 / 100
2736 ms188836 KiB
//Info1 fix code (fix 0707 2255)
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define all(v) v.begin(), v.end()
#define pb push_back
#define lb lower_bound
#define gibon ios::sync_with_stdio(false); cin.tie(0);
#define fi first
#define se second
#define pii pair<int, int>
#define pll pair<ll, ll>
typedef long long ll;
using namespace std;
const int mxN=200005;
const int mxM=99999;
const int mxK=60;
struct info{
    int plu[2], minu[2], notp, notm;
    info(){
        plu[0]=plu[1]=minu[0]=minu[1]=notp=notm=0;
    }
};
struct segtree{
    int seg[4*mxN]={};
    int typ;
    int f(int a, int b){
        if(a==0 || b==0) return a+b;
        if(typ==1) return max(a, b);
        if(typ==2) return min(a, b);
        // warning 방지용
        return 0;
    }
    void init(int n, int t){
        for(int i=0;i<4*n;i++) seg[i]=0;
        typ=t;
    }
    void upd(int idx, int s, int e, int pos, int x){
        if(s==e){
            seg[idx]=x;
            return;
        }
        int mid=(s+e)/2;
        if(pos<=mid) upd(2*idx, s, mid, pos, x);
        else upd(2*idx+1, mid+1, e, pos, x);
        seg[idx]=f(seg[2*idx], seg[2*idx+1]);
    }
    int solv(int idx, int s1, int e1, int s2, int e2){
        if(s2>e1 || s1>e2) return 0;
        if(s2<=s1 && e1<=e2) return seg[idx];
        int mid=(s1+e1)/2;
        return f(solv(2*idx, s1, mid, s2, e2), solv(2*idx+1, mid+1, e1, s2, e2));
    }
    int bin_search1l(int idx, int s1, int e1, int s2, int e2, int x){
        if(s1==e1){
            return (f(seg[idx], x)==seg[idx] ? s1 : 0);
        }
        if(s2>e1 || s1>e2) return 0;
        if(s2<=s1 && e1<=e2){
            if(f(seg[idx], x)==seg[idx]){
                int mid=(s1+e1)/2;
                int lres=bin_search1l(2*idx, s1, mid, s2, e2, x);
                if(lres!=0) return lres;
                return bin_search1l(2*idx+1, mid+1, e1, s2, e2, x);
            }
            else return 0;
        }
        int mid=(s1+e1)/2;
        if(s2<=mid){
            int lres=bin_search1l(2*idx, s1, mid, s2, e2, x);
            if(lres!=0) return lres;
        }
        return bin_search1l(2*idx+1, mid+1, e1, s2, e2, x);
    }
    int bin_search1r(int idx, int s1, int e1, int s2, int e2, int x){
        if(s1==e1){
            return (f(seg[idx], x)==seg[idx] ? s1 : 0);
        }
        if(s2>e1 || s1>e2) return 0;
        if(s2<=s1 && e1<=e2){
            if(f(seg[idx], x)==seg[idx]){
                int mid=(s1+e1)/2;
                int rres=bin_search1r(2*idx+1, mid+1, e1, s2, e2, x);
                if(rres!=0) return rres;
                return bin_search1r(2*idx, s1, mid, s2, e2, x);
            }
            else return 0;
        }
        int mid=(s1+e1)/2;
        if(s2<=mid){
            int lres=bin_search1r(2*idx+1, mid+1, e1, s2, e2, x);
            if(lres!=0) return lres;
        }
        return bin_search1r(2*idx, s1, mid, s2, e2, x);
    }
    int bin_search2l(segtree &Tp, int idx, int s1, int e1, int s2, int e2, int x1, int x2){
        if(s1==e1){
            return ((f(seg[idx], x1)==seg[idx] || Tp.f(Tp.seg[idx], x2)==Tp.seg[idx]) ? s1 : 0);
        }
        if(s2>e1 || s1>e2) return 0;
        if(s2<=s1 && e1<=e2){
            if(f(seg[idx], x1)==seg[idx] || Tp.f(Tp.seg[idx], x2)==Tp.seg[idx]){
                int mid=(s1+e1)/2;
                int lres=bin_search2l(Tp, 2*idx, s1, mid, s2, e2, x1, x2);
                if(lres!=0) return lres;
                return bin_search2l(Tp, 2*idx+1, mid+1, e1, s2, e2, x1, x2);
            }
            else return 0;
        }
        int mid=(s1+e1)/2;
        if(s2<=mid){
            int lres=bin_search2l(Tp, 2*idx, s1, mid, s2, e2, x1, x2);
            if(lres!=0) return lres;
        }
        return bin_search2l(Tp, 2*idx+1, mid+1, e1, s2, e2, x1, x2);
    }
    int bin_search2r(segtree &Tp, int idx, int s1, int e1, int s2, int e2, int x1, int x2){
        if(s1==e1){
            return ((f(seg[idx], x1)==seg[idx] || Tp.f(Tp.seg[idx], x2)==Tp.seg[idx]) ? s1 : 0);
        }
        if(s2>e1 || s1>e2) return 0;
        if(s2<=s1 && e1<=e2){
            if(f(seg[idx], x1)==seg[idx] || Tp.f(Tp.seg[idx], x2)==Tp.seg[idx]){
                int mid=(s1+e1)/2;
                int rres=bin_search2r(Tp, 2*idx+1, mid+1, e1, s2, e2, x1, x2);
                if(rres!=0) return rres;
                return bin_search2r(Tp, 2*idx, s1, mid, s2, e2, x1, x2);
            }
            else return 0;
        }
        int mid=(s1+e1)/2;
        if(s2<=mid){
            int rres=bin_search2r(Tp, 2*idx+1, mid+1, e1, s2, e2, x1, x2);
            if(rres!=0) return rres;
        }
        return bin_search2r(Tp, 2*idx, s1, mid, s2, e2, x1, x2);
    }
};
segtree Tp, Tm, Tmax1, Tmin1, Tmax2, Tmin2;
int N, Q;
pii A[mxN];
pii qry[mxN];
vector <array<int, 3>> v1;
vector <array<int, 3>> ct1;
info I[mxN][2]; // left info, right info
int lim[mxN][2][3]; // left limit, right limit, 각각 plu/ minu/ neutral

int zero[mxN][2][3][4];
// zero[i][j][k][l] = i번째 쿼리에 대해, (j=0: 왼쪽, j=1: 오른쪽)에서 봤을 때 (k=0: left, k=1: right, k=2: neutral limit의 오른쪽/왼쪽)에 (l=0: 0+, l=1: 0-, l=2: +0, l=3: -0)를 만족하는 가장 (왼쪽/오른쪽) 위치
int ans[mxN];
bool cmpp(pii a, pii b){return (a.fi<=b.fi && a.se>=b.se);} // a.fi<=b.fi인 a의 max(a.se)를 관리
bool cmpm(pii a, pii b){return (a.fi>=b.fi && a.se<=b.se);} // a.fi>=b.fi인 a의 min(a.se)를 관리
bool cmpnp(pii a, pii b){return (a.fi>=b.fi || a.se<=b.se);}// max(a.fi), min(a.se)를 관리
bool cmpnm(pii a, pii b){return (a.fi<=b.fi || a.se>=b.se);}// min(a.fi), max(a.se)를 관리
bool chkdir(pii a, pii b, int typ){
    if(typ==0 && a.fi==b.fi && a.se>=b.se) return true;
    if(typ==1 && a.fi==b.fi && a.se<=b.se) return true;
    if(typ==2 && a.fi>=b.fi && a.se==b.se) return true;
    if(typ==3 && a.fi<=b.fi && a.se==b.se) return true;
    return false;
}
void input(){
    cin >> N >> Q;
    for(int i=1;i<=N;i++) cin >> A[i].fi >> A[i].se;
    for(int i=1;i<=Q;i++) cin >> qry[i].fi >> qry[i].se;
}
void make_cr(){
    vector <int> cx, cy;
    for(int i=1;i<=N;i++) cx.push_back(A[i].fi), cy.push_back(A[i].se);
    sort(all(cx)), sort(all(cy));
    cx.erase(unique(all(cx)), cx.end());
    cy.erase(unique(all(cy)), cy.end());
    for(int i=1;i<=N;i++) A[i].fi=lower_bound(all(cx), A[i].fi)-cx.begin()+1, A[i].se=lower_bound(all(cy), A[i].se)-cy.begin()+1;
    for(int i=1;i<=Q;i++){
        int i1=lower_bound(all(cx), qry[i].fi)-cx.begin(), i2=lower_bound(all(cy), qry[i].se)-cy.begin();
        if(i1==cx.size() || i2==cy.size() || cx[i1]!=qry[i].fi || cy[i2]!=qry[i].se) qry[i]=pii(N+1, N+1);
        else qry[i]=pii(i1+1, i2+1);
    }
}
void make_segtree(){
    Tmin1.init(N, 2); Tmax1.init(N, 1); Tmin2.init(N, 2); Tmax2.init(N, 1);
    for(int i=1;i<=N;i++){
        Tmin1.upd(1, 1, N, i, A[i].fi);
        Tmax1.upd(1, 1, N, i, A[i].fi);
        Tmax2.upd(1, 1, N, i, A[i].se);
        Tmin2.upd(1, 1, N, i, A[i].se);
    }
}
void make_ct1(){
    for(int i=1;i<=N;i++) v1.push_back({A[i].fi, A[i].se, i});
    for(int i=1;i<=Q;i++) ct1.push_back({qry[i].fi, qry[i].se, i});
    sort(all(v1), [](array<int, 3> a, array<int, 3> b){return a[0]<b[0];});
}
int bin_search1(segtree &T, int l, int r, int val, bool lr){
    int allres=T.solv(1, 1, N, l, r);
    if(T.f(allres, val)!=allres) return 0;
    if(lr) return T.bin_search1l(1, 1, N, l, r, val);
    else return T.bin_search1r(1, 1, N, l, r, val);
}
int bin_search2(segtree &T1, segtree &T2, int l, int r, pii val, bool lr){ // left면 lr이 true
    pii allres=pii(T1.solv(1, 1, N, l, r), T2.solv(1, 1, N, l, r));
    if(T1.f(allres.fi, val.fi)!=allres.fi && T2.f(allres.se, val.se)!=allres.se) return 0;
    if(lr) return T1.bin_search2l(T2, 1, 1, N, l, r, val.fi, val.se);
    else return T1.bin_search2r(T2, 1, 1, N, l, r, val.fi, val.se);
}
void make_info1(){
    int vi;
    
    sort(all(ct1), [](array<int, 3> a, array<int, 3> b){return a[0]<b[0];});
    vi=0;
    Tp.init(N, 1), Tm.init(N, 2);
    for(auto [val1, val2, idx] : ct1){
        while(vi!=v1.size() && v1[vi][0]<=val1){
            Tp.upd(1, 1, N, v1[vi][2], v1[vi][1]);
            vi++;
        }
        I[idx][0].plu[0]=bin_search1(Tp, 1, N, val2, 1);
        if(I[idx][0].plu[0]!=0 && I[idx][0].plu[0]!=N) I[idx][0].plu[1]=bin_search1(Tp, I[idx][0].plu[0]+1, N, val2, 1);
        I[idx][0].notp=bin_search2(Tmax1, Tmin2, 1, N, pii(val1, val2), 1);
        I[idx][0].notm=bin_search2(Tmin1, Tmax2, 1, N, pii(val1, val2), 1);

        I[idx][1].plu[0]=bin_search1(Tp, 1, N, val2, 0);
        if(I[idx][1].plu[0]!=0 && I[idx][1].plu[0]!=1) I[idx][1].plu[1]=bin_search1(Tp, 1, I[idx][0].plu[0]-1, val2, 0);
        I[idx][1].notp=bin_search2(Tmax1, Tmin2, 1, N, pii(val1, val2), 0);
        I[idx][1].notm=bin_search2(Tmin1, Tmax2, 1, N, pii(val1, val2), 0);
    }
    reverse(all(ct1));
    vi=N-1;
    for(auto [val1, val2, idx] : ct1){
        while(vi!=-1 && v1[vi][0]>=val1){
            Tm.upd(1, 1, N, v1[vi][2], v1[vi][1]);
            vi--;
        }
        I[idx][0].minu[0]=bin_search1(Tm, 1, N, val2, 1);
        if(I[idx][0].minu[0]!=0 && I[idx][0].minu[0]!=N) I[idx][0].minu[1]=bin_search1(Tm, I[idx][0].minu[0]+1, N, val2, 1);
        I[idx][1].minu[0]=bin_search1(Tm, 1, N, val2, 0);
        if(I[idx][1].minu[0]!=0 && I[idx][1].minu[0]!=1) I[idx][1].minu[1]=bin_search1(Tm, 1, I[idx][0].minu[0]-1, val2, 0);
    }
}
void make_lim(){
    for(int i=1;i<=Q;i++){
        info li=I[i][0], ri=I[i][1];

        //-- left limit
        if(li.plu[0]!=0 && (li.plu[0]==1 || (li.notm!=0 && li.plu[0]>li.notm))) lim[i][0][0]=li.plu[0];
        else if(li.plu[1]!=0) lim[i][0][0]=li.plu[1];
        if(li.minu[0]!=0 && (li.minu[0]==1 || (li.notp!=0 && li.minu[0]>li.notp))) lim[i][0][1]=li.minu[0];
        else if(li.minu[1]!=0) lim[i][0][1]=li.minu[1];
        if(li.notp!=0 && li.notm!=0) lim[i][0][2]=max(li.notp, li.notm);

        //-- right limit
        if(ri.plu[0]!=0 && (ri.plu[0]==N || (ri.notm!=0 && ri.plu[0]<ri.notm))) lim[i][1][0]=ri.plu[0];
        else if(ri.plu[1]!=0) lim[i][1][0]=ri.plu[1];
        if(ri.minu[0]!=0 && (ri.minu[0]==N || (ri.notp!=0 && ri.minu[0]<ri.notp))) lim[i][1][1]=ri.minu[0];
        else if(ri.minu[1]!=0) lim[i][1][1]=ri.minu[1];
        if(ri.notp!=0 && ri.notm!=0) lim[i][1][2]=min(ri.notp, ri.notm);
    }
}
vector <pii> v2[2][mxN];
vector <array<int, 4>> ct2[2][2][mxN];
segtree T0max, T0min;
// ct2[i][j][k]: (a[0], N] /i/ [1, a[0])에 있는 값들 중 (k, a[1]+), (k, a[1]-) /j/ (a[1]+, k), (a[1]-, k)인 값 찾아서 zero[a[2]][j][a[3]]에 넣기 (ct2[0]: left, ct2[1]: right)
void make_zero(){
    T0max.init(N, 1), T0min.init(N, 2);
    for(int i=1;i<=N;i++) v2[0][A[i].fi].emplace_back(A[i].se, i), v2[1][A[i].se].emplace_back(A[i].fi, i);

    for(int i=1;i<=Q;i++){
        for(int j=0;j<2;j++) for(int k=0;k<3;k++) if(lim[i][j][k]!=0){
            ct2[j][0][qry[i].fi].push_back({lim[i][j][k], qry[i].se, i, k});
            ct2[j][1][qry[i].se].push_back({lim[i][j][k], qry[i].fi, i, k});
        } 
    }
    for(int i=1;i<=N;i++){
        for(int j=0;j<2;j++){
            for(auto [y, idx] : v2[j][i]){
                T0max.upd(1, 1, N, idx, y);
                T0min.upd(1, 1, N, idx, y);
            }
            for(int dir=0;dir<=1;dir++){
                for(auto [pos, val, idx1, idx2] : ct2[dir][j][i]){
                    if(j==0 && dir==0 && pos!=N) zero[idx1][dir][idx2][0]=bin_search1(T0max, pos+1, N, val, 1);
                    if(j==0 && dir==1 && pos!=1) zero[idx1][dir][idx2][0]=bin_search1(T0max, 1, pos-1, val, 0);
                    if(j==0 && dir==0 && pos!=N) zero[idx1][dir][idx2][1]=bin_search1(T0min, pos+1, N, val, 1);
                    if(j==0 && dir==1 && pos!=1) zero[idx1][dir][idx2][1]=bin_search1(T0min, 1, pos-1, val, 0);
                    if(j==1 && dir==0 && pos!=N) zero[idx1][dir][idx2][2]=bin_search1(T0max, pos+1, N, val, 1);
                    if(j==1 && dir==1 && pos!=1) zero[idx1][dir][idx2][2]=bin_search1(T0max, 1, pos-1, val, 0);
                    if(j==1 && dir==0 && pos!=N) zero[idx1][dir][idx2][3]=bin_search1(T0min, pos+1, N, val, 1);
                    if(j==1 && dir==1 && pos!=1) zero[idx1][dir][idx2][3]=bin_search1(T0min, 1, pos-1, val, 0);
                }
            }
            for(auto [y, idx] : v2[j][i]){
                T0max.upd(1, 1, N, idx, 0);
                T0min.upd(1, 1, N, idx, 0);
            }
        }
    }
}
vector <pair<pii, int>> v00, vq;
segtree T3max, T3min;
bool possible(array<bool, 3> lcond, array<bool, 3> rcond, array<bool, 3> mcond, bool dir1, bool dir2){ // dir: (0+) or (-0), cond: + - 0
    if(mcond[0] && mcond[1]) return true;
    bool lp=(lcond[0] || (dir1 && lcond[2])), lm=(lcond[1] || (!dir1 && lcond[2]));
    bool rp=(rcond[0] || (dir2 && rcond[2])), rm=(rcond[1] || (!dir2 && rcond[2]));
    if(mcond[0] && (lm || rm)) return true;
    if(mcond[1] && (lp || rp)) return true;
    if((lp && rm) || (rp && lm)) return true;
    return false;
}
bool f(int idx, int lpos, int rpos, bool dir1, bool dir2){
    if(lpos==0 || rpos==0 || lpos>=rpos) return false;
    array<bool, 3> lcond, rcond, mcond={0, 0, 1};
    for(int j=0;j<3;j++) lcond[j]=(lim[idx][0][j]!=0 && lpos>lim[idx][0][j]);
    for(int j=0;j<3;j++) rcond[j]=(lim[idx][1][j]!=0 && rpos<lim[idx][1][j]);
    if(lpos==1) lcond[2]=1;
    if(rpos==N) rcond[2]=1;
    if(lpos==rpos-1){
        mcond[0]=mcond[1]=0;
    }
    else{
        int resp=T3max.solv(1, 1, N, lpos+1, rpos-1);
        mcond[0]=(resp!=0 && resp>=qry[idx].se);
        int resm=T3min.solv(1, 1, N, lpos+1, rpos-1);
        mcond[1]=(resm!=0 && resm<=qry[idx].se);
    }
    return possible(lcond, rcond, mcond, dir1, dir2);
}
void solv(){ // 나중에 sweeping으로 교체
    for(int i=1;i<=N;i++) v00.emplace_back(A[i], i);
    for(int i=1;i<=Q;i++) vq.emplace_back(qry[i], i);
    sort(all(v00)), sort(all(vq));
    T3max.init(N, 1), T3min.init(N, 2);
    int ulc=0, urc=0;
    for(int i=1;i<=N;i++) T3min.upd(1, 1, N, i, A[i].se);
    pii lqry[16], rqry[16];
    int lqi, rqi;
    int lc=0, rc=0;
    for(auto [qval, i] : vq){
        //-- segtree upd
        while(ulc!=N && v00[ulc].fi.fi<qval.fi){
            T3min.upd(1, 1, N, v00[ulc].se, 0);
            ulc++;
        }
        while(urc!=N && v00[urc].fi.fi<=qval.fi){
            T3max.upd(1, 1, N, v00[urc].se, v00[urc].fi.se);
            urc++;
        }
        // -- 00 case
        while(lc!=N && v00[lc].fi<qval) lc++;
        while(rc!=N && (v00[rc].fi<qval || v00[rc].fi==qval)) rc++;
        if(rc>=lc+3){
            ans[i]=1;
            continue;
        }
        for(int j=lc;j<rc;j++){
            int pos=v00[j].se;
            bool lnotp=(I[i][0].notp!=0 && I[i][0].notp<pos), lnotm=(I[i][0].notm!=0 && I[i][0].notm<pos);
            bool rnotp=(I[i][1].notp!=0 && I[i][1].notp>pos), rnotm=(I[i][1].notm!=0 && I[i][1].notm>pos);
            if(pos==1) lnotp=true, lnotm=true;
            if(pos==N) rnotp=true, rnotm=true;
            if(lnotp && lnotm && rnotp && rnotm) ans[i]=1;
        }
        if(ans[i]==1) continue;

        //-- 0x, x0 case 
        for(int j=0;j<16;j++) lqry[j]=rqry[j]=pii();
        lqi=0, rqi=0;
        for(int llvl=0;llvl<3;llvl++) for(int dir1=0;dir1<4;dir1++){
            int lpos=zero[i][0][llvl][dir1];
            if(lpos!=0) lqry[lqi++]={lpos, dir1};
        }
        if(A[1].fi==qry[i].fi || A[1].se==qry[i].se){
            for(int j=0;j<4;j++) if(chkdir(A[1], qry[i], j)){
                lqry[lqi++]={1, j};
            } 
        }
        for(int rlvl=0;rlvl<3;rlvl++) for(int dir2=0;dir2<4;dir2++){
            int rpos=zero[i][1][rlvl][dir2];
            if(rpos!=0) rqry[rqi++]={rpos, dir2};
        }
        if(A[N].fi==qry[i].fi || A[N].se==qry[i].se){
            for(int j=0;j<4;j++) if(chkdir(A[N], qry[i], j)){
                rqry[rqi++]={N, j};
            }
        }
        for(int j=0;j<lqi;j++) for(int k=0;k<rqi;k++){
            if(ans[i]==1) break;
            auto [lpos, dir1]=lqry[j];
            auto [rpos, dir2]=rqry[k];
            if((dir1<2 && dir2<2) || (dir1>=2 && dir2>=2)) continue;
            if(f(i, lpos, rpos, (dir1==0 || dir1==3), (dir2==0 || dir2==3))) ans[i]=1;
        }

    }
}
int main(){
    gibon
    input();
    make_cr();
    make_segtree();
    make_ct1();
    make_info1();
    make_lim();
    make_zero();
    solv();
    for(int i=1;i<=Q;i++) if(ans[i]) cout << i << " ";
}

Compilation message (stderr)

Main.cpp: In function 'void make_cr()':
Main.cpp:176:14: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  176 |         if(i1==cx.size() || i2==cy.size() || cx[i1]!=qry[i].fi || cy[i2]!=qry[i].se) qry[i]=pii(N+1, N+1);
      |            ~~^~~~~~~~~~~
Main.cpp:176:31: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  176 |         if(i1==cx.size() || i2==cy.size() || cx[i1]!=qry[i].fi || cy[i2]!=qry[i].se) qry[i]=pii(N+1, N+1);
      |                             ~~^~~~~~~~~~~
Main.cpp: In function 'void make_info1()':
Main.cpp:213:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::array<int, 3> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  213 |         while(vi!=v1.size() && v1[vi][0]<=val1){
      |               ~~^~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...