Codeforces Round #424 E. Cards Sorting

本文介绍了一个涉及牌堆操作的问题解决方案,使用vector记录数值位置并排序,通过线段树或树状数组维护区间状态,实现高效查找与删除最小值。

题意 : 给你N张牌,操作为拿起牌顶的牌,若当前牌的数值是最小的,就扔掉它,否则将牌放到牌堆底,问扔完所有牌需要多少次操作。

这个题肯定是从小到大删除,可以用一个 vector 保存每一个数的下标然后给每一个数的下标从小到大排个序(这样可以用O(1)时间内找到要删掉下一个的位置 ),用线段树或者树状数组维护每个区间内有多少个数没有背删去 (单点修改,区间查询)。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#define ll long long
using namespacestd;
const int maxn =1e5 + 10;
struct node {
    int l,r;
    int sum;
}tr[maxn <<2];
struct point {
    int pos;
    int cnt;
};
ll ans = 0;
vector <int> a[maxn];
void build (int l,int r,int root) {
    tr[root].l = l;
    tr[root].r = r;
    if (l == r) {
        tr[root].sum =1;
        return;
    }
    int mid = (l + r) >>1;
    build(l, mid, root <<1);
    build(mid +1, r, root << 1 |1);
    tr[root].sum =tr[root << 1].sum +tr[root << 1 |1].sum;
//    return ;
}
void update (int pos,int root) {
    if (tr[root].l ==tr[root].r) {
        tr[root].sum =0;
        return;
    }
    int mid = (tr[root].l +tr[root].r) >>1;
    if (pos > mid) update(pos, root << 1 | 1);
    else update(pos, root << 1);
    tr[root].sum =tr[root << 1].sum +tr[root << 1 |1].sum;
}
int query (int l,int r,int root) {
    if (l > r)return 0;
    if (tr[root].l >= l &&tr[root].r <= r) {
        returntr[root].sum;
    }
    int mid = (tr[root].l +tr[root].r) >>1;
    if (l > mid)return query(l, r, root <<1 | 1);
    else if (r <= mid) returnquery(l, r, root << 1);
    else return query(l, r, root <<1) + query(l, r, root <<1 | 1);
}

int main () {
    ios_base ::sync_with_stdio(false);
    int n;
    cin >> n;
    build(1, n,1);
    int mi =maxn;
    for (int i =1;i <= n; ++ i) {
        int x;
        cin >> x;
        mi = min (mi,x);
        a[x].push_back (i);
    }
    for (int i = mi;i <maxn; ++ i) {
        if (a[i].size()){
//            cout << i << ' ' << a[i][0] << endl;
            sort (a[i].begin(),a[i].end());
        }
    }
    int pos =0;
    for (int i = mi;i <maxn; ++ i) {
        if (a[i].size ()) {
            int u =a[i].size();
            int cnt =0;
            int j =lower_bound (a[i].begin(),a[i].end(),pos) - a[i].begin();
//            cout << j << ' ' << a[i][j] << ' ';
            if (j != u){
            if (pos !=a[i][j])
                ans +=query(pos + 1,a[i][j],1);
            }
            else {
                j = 0;
                ans +=query(pos + 1, n,1);
                ans +=query(1,a[i][j],1);
            }
//            cout << ans << endl;
            update(a[i][j],1);
            pos = a[i][j];
            for (int k =0;k < u - 1;++k) {
                if (j != u -1) {
                    j ++;
                    ans +=query(pos + 1,a[i][j],1);
                    update(a[i][j],1);
                    pos = a[i][j];
                }
                else {
                    j = 0;
                    ans +=query(1,a[i][j],1);
                    ans +=query(pos + 1, n,1);
                    pos = a[i][j];
                    update(a[i][j],1);
                }
            }
        }
    }
    cout <<ans << endl;
    return0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值