CodeForces830B【树状数组+线段树】

思路:
就是 你好像就是要维护一下,你pop的当前值与之前的pop值的位置之间有多少个要移一移,然后算一下,然后就变成了模拟。。
线段树维护 值 和 位置,树状数组维护已经取了没有。

7
6 3 1 5 4 4 3

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
int val[N], n;
struct Seg{
    int id;
    int w;
    int Left, Right;
}node[N<<2];

void Build(int num, int Left, int Right){
    node[num].Left = Left;
    node[num].Right = Right;
    if(Left == Right){
        node[num].id = Left;
        node[num].w = val[Left];
        return;
    }
    int Mid = (Left + Right) >> 1;
    Build(num<<1, Left, Mid);
    Build(num<<1|1, Mid + 1, Right);
    node[num].w = node[num<<1].w < node[num<<1|1].w?node[num<<1].w:node[num<<1|1].w;
    node[num].id = node[num<<1].w < node[num<<1|1].w?node[num<<1].id:node[num<<1|1].id;
    if(node[num<<1].w == node[num<<1|1].w)
        node[num].id = node[num<<1].id < node[num<<1|1].id?node[num<<1].id:node[num<<1|1].id;
}

void Update(int num, int v){
    if(node[num].Left == node[num].Right){
        if(node[num].Left == v){
            node[num].w = INF;
        }
        return;
    }
    int Mid = (node[num].Left + node[num].Right) >> 1;
    if(Mid >= v) Update(num<<1, v);
    else Update(num<<1|1, v);
    node[num].w = node[num<<1].w < node[num<<1|1].w?node[num<<1].w:node[num<<1|1].w;
    node[num].id = node[num<<1].w < node[num<<1|1].w?node[num<<1].id:node[num<<1|1].id;
    if(node[num<<1].w == node[num<<1|1].w)
        node[num].id = node[num<<1].id < node[num<<1|1].id?node[num<<1].id:node[num<<1|1].id;
}

Seg Query(int num, int s, int t){
    if(node[num].Left >= s && node[num].Right <= t)
        return node[num];
    int Mid = (node[num].Left + node[num].Right) >> 1;
    if(Mid >= t) return Query(num<<1, s, t);
    else if(Mid < s) return Query(num<<1|1, s, t);
    else{
        Seg temp1,temp2;
        temp1 = Query(num<<1, s, Mid);
        temp2 = Query(num<<1|1, Mid+1, t);
        if(temp1.w < temp2.w) return temp1;
        if(temp1.w == temp2.w){
            if(temp1.id < temp2.id) return temp1;
            return temp2;
        }
        return temp2;
    }
}

LL c[N];
int lowbit(int v){
    return v&(-v);
}
LL Sum(int v){
    LL res = 0;
    while(v>0){
        res += c[v];
        v-=lowbit(v);
    }
    return res;
}
void add(int v,LL x){
    while(v<=n){
        c[v] += x;
        v += lowbit(v);
    }
}
LL kk(int pre, int now){
    if(pre == now) return 1LL;
    LL res = 0;
    if(now > pre)
        return Sum(now) - Sum(pre);
    else
        return Sum(n) - Sum(pre) + Sum(now);
}

void solve(){
    LL res = 0;
    Seg temp;
    int sum = 1;
    int Mimi, pos;
    int Last = 1;
    while(sum <= n){
        Mimi = val[sum];
        temp = Query(1,Last, n);
        if(temp.w == val[sum]){
            res = res + kk(Last-1, temp.id);
            add(temp.id, -1);
            Update(1, temp.id);
            Last = temp.id;
        }
        else{
            temp = Query(1,1, Last-1);
            res = res + kk(Last, temp.id);
            add(temp.id, -1);
            Update(1,temp.id);
            Last = temp.id;
        }
        sum++;
    }
    printf("%lld\n",res);
}

int main(){
    scanf("%d", &n);
    for(int i=1;i<=n;i++){
        add(i,1LL);
        scanf("%d",&val[i]);
    }
    Build(1,1,n);
    sort(val+1, val+n+1);
    solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值