带修主席树(树状数组 套 主席树)

166 篇文章 0 订阅

今天上课,,很是无聊,所以,手写了一个模板题,但是常数有点大,,

可能结构体都是这个样子吧,,虽然简单,但是常数大。

题目描述

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

输入格式

输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。

输出格式

输出包含m行,依次为删除每个元素之前,逆序对的个数。

输入输出样例

输入 #1复制

5 4
1
5
3
4
2
5
1
4
2

输出 #1复制

5
2
2
1

样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

说明/提示

N<=100000 M<=50000

 

#include<bits/stdc++.h>
using namespace std;
const int M=1e5+50;
struct Node{int l,r,sum;}t[M*210];
int pos[M],n,m,rt[M],d[M],cnt,t0[M];
long long res;
void add(int &now,int l,int r,int pos,int v){
    if(!now)now=++cnt;
    t[now].sum+=v;
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(pos<=mid)add(t[now].l,l,mid,pos,v);
    if(mid<pos)add(t[now].r,mid+1,r,pos,v);
}
void Add(int x,int pos,int v){
    while(x<=n){
        add(rt[x],1,n,pos,v);
        x+=(x&-x);
    }
}
long long ask(int x,int ll,int rr,int l,int r){
    if(l>r||!x)return 0;
    if(l<=ll&&rr<=r)return t[x].sum;
    int mid=(ll+rr)>>1;
    long long ans=0;
    if(l<=mid)ans+=ask(t[x].l,ll,mid,l,r);
    if(mid<r)ans+=ask(t[x].r,mid+1,rr,l,r);
    return ans;
}
long long Ask(int x,int l,int r){
    long long ans=0;
    while(x>0){
        ans+=ask(rt[x],1,n,l,r);
        x-=(x&-x);
    }
    return ans;
}
void query(int x){
    res-=Ask(pos[x]-1,x+1,n);
    res-=Ask(n,1,x-1)-Ask(pos[x],1,x-1);
}
void add0(int x){  while(x<=n) t0[x]++,x+=(x&-x);}
long long sum0(int x){long long ans=0; while(x){ ans+=t0[x]; x-=(x&-x);} return ans;}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&d[i]),Add(i,d[i],1),pos[d[i]]=i;

    for(int i=1;i<=n;i++) res+=i-1-sum0(d[i]),add0(d[i]);

    for(int x,i=1;i<=m;i++){
        printf("%lld\n",res);
        scanf("%d",&x);
        query(x);
        Add(pos[x],x,-1);
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值