0w1

CFR 622 C. Not Equal on a Segment ( TLE Mo's / AC Segment Tree )

Problem - C - Codeforces
すぐに思いついたのが mo'sだったが、実装が下手すぎてTLEした。
でも自分の書き方のバグに気付いた。
以前は
int lb = 2, rb = 1; みたいなもの書いてすぐ適当に尺取りしていたが、
もしさきに lbを縮ませてしまうとまだ何も入ってないのでREしてしまいます。
int lb = 1, rb = 0; と書いて先に右へ動かせましょう。

// TLE
#include <bits/stdc++.h>
#pragma optimize ("O3")
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXM = 2e5 + 5;
const int MAXA = 1e6 + 6;

int n, m;
int a[ MAXN ];

int BLK_SIZE;
int blk[ MAXN ];
struct Query{
    int id;
    int ql, qr, v;
    Query(int _l = -1, int _r = -1, int v = 0){}
    bool operator < (const Query &oth) const{
        if( blk[ ql ] != blk[ oth.ql ] )
            return blk[ ql ] < blk[ oth.ql ];
        return qr < oth.qr;
    }
} qry[ MAXM ];

multiset< int > has;
multiset< int > vis[ MAXA ];
int ans[ MAXM ];

void solve(){
    BLK_SIZE = sqrt( m ) + 1;
    for(int i = 1; i <= n; ++i)
        blk[ i ] = ( i - 1 ) / BLK_SIZE;
    sort( qry, qry + m );
    int lb = 1, rb = 0;
    for(int i = 0; i < m; ++i){
        int ql = qry[ i ].ql, qr = qry[ i ].qr;
        while( rb < qr ){
            ++rb;
            vis[ a[ rb ] ].insert( rb );
            has.insert( a[ rb ] );
        }
        while( rb > qr ){
            vis[ a[ rb ] ].insert( rb );
            has.erase( has.find( a[ rb ] ) );
            --rb;
        }
        while( lb > ql ){
            --lb;
            vis[ a[ lb ] ].insert( lb );
            has.insert( a[ lb ] );
        }
        while( lb < ql ){
            vis[ a[ lb ] ].erase( lb );
            has.erase( has.find( a[ lb ] ) );
            ++lb;
        }
        if( *has.begin() != qry[ i ].v )
            ans[ qry[ i ].id ] = *vis[ *has.begin() ].begin();
        else if( *( --has.end() ) != qry[ i ].v )
            ans[ qry[ i ].id ] = *vis[ *( --has.end() ) ].begin();
        else
            ans[ qry[ i ].id ] = -1;
    }
    for(int i = 0; i < m; ++i)
        printf("%d\n", ans[ i ]);
}

void readInt(int &x){
    char c; while( ( c = getchar() ) < '0' );
    for(x = c - '0'; ( c = getchar() ) >= '0'; x = x * 10 + c - '0');
}

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i)
        readInt( a[ i ] ); // scanf("%d", &a[ i ]);
    for(int i = 0; i < m; ++i){
        qry[ i ].id = i;
        // scanf("%d%d%d", &qry[ i ].ql, &qry[ i ].qr, &qry[ i ].v);
        readInt( qry[ i ].ql ), readInt( qry[ i ].qr ), readInt( qry[ i ].v );
    }
    solve();
    return 0;
}

RMQ だけで処理するのが想定解らしい

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXM = 2e5 + 5;
const int MAXA = 1e6 + 6;
const int INF = 1e9;
typedef pair< int, int > pii;

int n, m;
int a[ MAXN ];

struct itvt{
    int minv, maxv;
    int min_idx, max_idx;
    int lb, rb;
    itvt *lc, *rc;
    itvt(int _l = -1, int _r = -1){
        lb = _l, rb = _r;
        minv = INF;
        maxv = -INF;
        lc = rc = NULL;
    }
    void pull(){
        if( lc->minv < rc->minv ){
            minv = lc->minv;
            min_idx = lc->min_idx;
        } else{
            minv = rc->minv;
            min_idx = rc->min_idx;
        }
        if( lc->maxv > rc->maxv ){
            maxv = lc->maxv;
            max_idx = lc->max_idx;
        } else{
            maxv = rc->maxv;
            max_idx = rc->max_idx;
        }
    }
    pii qmin(int ql, int qr){
        if( qr < lb || rb < ql ) return pii( INF, INF );
        if( ql <= lb && rb <= qr ) return pii( minv, min_idx );
        return min( lc->qmin( ql, qr ), rc->qmin( ql, qr ) );
    }
    pii qmax(int ql, int qr){
        if( qr < lb || rb < ql ) return pii( -INF, -INF );
        if( ql <= lb && rb <= qr ) return pii( maxv, max_idx );
        return max( lc->qmax( ql, qr ), rc->qmax( ql, qr ) );
    }
} *root;

itvt* buildItvt(int lb, int rb){
    itvt *t = new itvt( lb, rb );
    if( lb == rb ){
        t->minv = t->maxv = a[ lb ];
        t->min_idx = t->max_idx = lb;
        return t;
    }
    int mid = lb + rb >> 1;
    t->lc = buildItvt( lb, mid );
    t->rc = buildItvt( mid + 1, rb );
    t->pull();
    return t;
}

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i)
        scanf("%d", a + i);
    root = buildItvt( 1, n );
    for(int i = 0; i < m; ++i){
        int l, r, x; scanf("%d%d%d", &l, &r, &x);
        pii mn = root->qmin( l, r );
        pii mx = root->qmax( l, r );
        if( mn.first != x ) printf("%d\n", mn.second);
        else if( mx.first != x ) printf("%d\n", mx.second);
        else puts("-1");
    }
    return 0;
}