#LOJ2319. 「NOIP2017」列队 线段树 动态开点

题目描述

这个题有点 exciting e x c i t i n g 啊 用 vectorO(n) v e c t o r O ( n ) erase e r a s e 竟然能过 90pts 90 p t s

首先我们可以把这个矩阵拆成 n×(m1)+1×n n × ( m − 1 ) + 1 × n
对于每一行的前 m1 m − 1 个元素开一棵线段树
最后一列的元素单独开一棵线段树

线段树维护的是区间中的某一个元素是否被删除

因为空节点全是 0 0 所以我们很好就可以用1来表示删除了这个位置

后来插入的怎么办呢 我们对于每个线段树再开一个 vector v e c t o r 维护后来插入的元素的值,询问的时候判断一下元素是否变动过就好了

时间复杂度 O(nlogn) O ( n l o g n )

Codes
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

namespace In  {
# define In_Len 80000000
    static std :: streambuf* fb ( std :: cin.rdbuf ( ) ) ;
    static char buf [In_Len], *ss ( 0 ) ;

    void init ( )  {  fb -> sgetn ( ss = buf, In_Len ) ;  }

    inline int read ( )  {
        register int x ;
        bool opt ( 1 ) ;
        while ( isspace ( *ss ) )  ++ ss ;
        if ( *ss == 45 )  { ++ ss ; opt = 0 ; }
        for ( x = -48 + *ss ; isdigit ( * ++ ss ) ; ( x *= 10 ) += *ss - 48 ) ; ++ ss ;
        return opt ? x : -x ;
    }
# undef In_Len
}

namespace Out  {
# define Out_Len 80000000
    static std :: streambuf* fb ( std :: cout.rdbuf ( ) ) ;
    static char buf [Out_Len], *ss ( buf ) ;

    inline void print ( register ll x )  {
        static int T [60], tp ( 0 ) ;
        if ( ! x )  {  *ss ++ =  48 ; *ss ++ = 10 ; return ;  }
        if ( x < 0 )  {  *ss ++ = 45 ; x = -x ;  }
        while ( x ) T [++ tp] = x % 10 | 48, x /= 10 ;
        while ( tp )  *ss ++ = T [tp --] ;
        *ss ++ = 10 ;
    }

    inline void flush ( )  {  fb -> sputn ( buf, ss - buf ) ;  }

# undef Out_Len
}

const int N = 3e5 + 10, M = 4e7 + 10;
int n, m, q, num;
int root[N];
vector<ll> vec[N];

struct Segment_Tree {
#define ls(x) (T[x].ch[0])
#define rs(x) (T[x].ch[1])
#define mid ((l + r) >> 1)
    int cnt; 

    struct node {
        int ch[2], sum; 
    }T[M]; 

    void update(int &x, int l, int r, int p) {
        if(!x) x = ++ cnt; ++ T[x].sum; 
        if(l == r) return;
        if(p <= mid) update(ls(x), l, mid, p);
        else update(rs(x), mid + 1, r, p);
    }

    int query(int &x, int l, int r, int p) {
        if(l == r) return l;                    
        int res = mid - l + 1 - T[ls(x)].sum;
        if(res >= p) return query(ls(x), l, mid, p);
        else return query(rs(x), mid + 1, r, p - res);
    }

    int Sum(int x) {
        if(x > n) return n - T[root[x]].sum;
        return m - 1 - T[root[x]].sum;
    }

}T;


int main() {
#ifndef ONLINE_JUDGE
    freopen("2319.in", "r", stdin);
    freopen("2319.out", "w", stdout);
#endif
    int x, y; ll ans, ANS;
    In::init();
    n = In::read(), m = In::read(), q = In::read();
    num = max(n, m) + q;
    for(int i = 1; i <= q; ++ i) {
        x = In::read(), y = In::read();
        if(y != m) {
            ans = T.query(root[x], 1, num, y);
            T.update(root[x], 1, num, ans);
            ans = ans <= (m - 1) ? ans + (ll)m * (x - 1) : vec[x][ans - m];
            ANS = T.query(root[n + 1], 1, num, x);
            T.update(root[n + 1], 1, num, ANS);
            ANS = ANS <= n ? ANS * m : vec[n + 1][ANS - n - 1];
            vec[x].push_back(ANS), vec[n + 1].push_back(ans);
        }
        else {
            ans = T.query(root[n + 1], 1, num, x);
            T.update(root[n + 1], 1, num, ans);
            ans = ans <= n ? ans * m : vec[n + 1][ans - n - 1];
            vec[n + 1].push_back(ans);
        }
        Out::print(ans);    
    }
    Out::flush();
    cerr << 1.0 * clock() / CLOCKS_PER_SEC << endl;
    return 0;
}

顺便附上我 O(nm) O ( n m ) 的暴力

这里写图片描述

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

namespace In  {
# define In_Len 80000000
    static std :: streambuf* fb ( std :: cin.rdbuf ( ) ) ;
    static char buf [In_Len], *ss ( 0 ) ;

    void init ( )  {  fb -> sgetn ( ss = buf, In_Len ) ;  }

    inline int read ( )  {
        register int x ;
        bool opt ( 1 ) ;
        while ( isspace ( *ss ) )  ++ ss ;
        if ( *ss == 45 )  { ++ ss ; opt = 0 ; }
        for ( x = -48 + *ss ; isdigit ( * ++ ss ) ; ( x *= 10 ) += *ss - 48 ) ; ++ ss ;
        return opt ? x : -x ;
    }
# undef In_Len
}

namespace Out  {
# define Out_Len 80000000
    static std :: streambuf* fb ( std :: cout.rdbuf ( ) ) ;
    static char buf [Out_Len], *ss ( buf ) ;

    inline void print ( register ll x )  {
        static int T [60], tp ( 0 ) ;
        if ( ! x )  {  *ss ++ =  48 ; *ss ++ = 10 ; return ;  }
        if ( x < 0 )  {  *ss ++ = 45 ; x = -x ;  }
        while ( x ) T [++ tp] = x % 10 | 48, x /= 10 ;
        while ( tp )  *ss ++ = T [tp --] ;
        *ss ++ = 10 ;
    }

    inline void flush ( )  {  fb -> sputn ( buf, ss - buf ) ;  }

# undef Out_Len
}

const int N = 3e5 + 10, M = 4e7 + 10;
int n, m, q;
int root[N];
vector<ll> vec[N];

struct Segment_Tree {
#define ls(x) (T[x].ch[0])
#define rs(x) (T[x].ch[1])
#define mid ((l + r) >> 1)
    int cnt; 

    struct node {
        int ch[2], sum; 
    }T[M]; 

    void update(int &x, int l, int r, int p) {
        if(!x) x = ++ cnt; ++ T[x].sum; 
        if(l == r) return;
        if(p <= mid) update(ls(x), l, mid, p);
        else update(rs(x), mid + 1, r, p);
    }

    int query(int &x, int l, int r, int p) {
        if(l == r) return l;                    
        int res = mid - l + 1 - T[ls(x)].sum;
        if(res >= p) return query(ls(x), l, mid, p);
        else return query(rs(x), mid + 1, r, p - res);
    }

    int Sum(int x) {
        if(x > n) return n - T[root[x]].sum;
        return m - 1 - T[root[x]].sum;
    }

}T;


int main() {
#ifndef ONLINE_JUDGE
    freopen("2319.in", "r", stdin);
    freopen("2319.out", "w", stdout);
#endif
    int x, y; ll ans, ANS;
    In::init();
    n = In::read(), m = In::read(), q = In::read();
    for(int i = 1; i <= q; ++ i) {
        x = In::read(), y = In::read();
        if(y != m) {
            int ovo = T.Sum(x), qaq = T.Sum(n + 1); 
            if(y <= ovo) {  
                ans = T.query(root[x], 1, m - 1, y);
                T.update(root[x], 1, m - 1, ans);
                ans += 1ll * (x - 1) * m;
            }
            else {
                ans = vec[x][y - ovo - 1];
                vec[x].erase(vec[x].begin() + y - ovo - 1);
            }
            if(x <= qaq) {
                ANS = T.query(root[n + 1], 1, n, x);
                T.update(root[n + 1], 1, n, ANS);
                ANS *= m;
            }
            else {
                ANS = vec[n + 1][x - qaq - 1];
                vec[n + 1].erase(vec[n + 1].begin() + x - qaq - 1);
            }
        //  cout << ans << ' ' << ANS << endl;
            vec[x].push_back(ANS), vec[n + 1].push_back(ans);
        }
        else {
            int qaq = T.Sum(n + 1);
            if(x <= qaq) {
                ans = T.query(root[n + 1], 1, n, x);
                T.update(root[n + 1], 1, n, ans);
                ans *= m;
            }
            else {
                ans = vec[n + 1][x - qaq - 1];
                vec[n + 1].erase(vec[n + 1].begin() + x - qaq - 1);
            }
            vec[n + 1].push_back(ans);
        }
        Out::print(ans);    
    }
    Out::flush();
    return 0;
}

我好菜啊马上就 noip2018 n o i p 2018 了 我今天才改完 noip2017 n o i p 2017 的题目 qaq q a q

暴力出奇迹还是没错了, noip n o i p 实在复杂度不对卡一卡说不定就 A A <script type="math/tex" id="MathJax-Element-689">A</script>了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值