uva11990 线段树套树状数组

题意:给一个1-n的排列,按照某种顺序一些数(其他数顺序不变),输出每次删除之前逆序对的数目。

分析:线段树每个节点表示的一段数字排序,每个节点用树状数组维护删除的点。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#define inf 1000000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
using namespace std;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef long long ll;
const int maxn=200005;
int n,m;
int order[30][maxn];
int tree[30][maxn];
int pos[maxn];
ll ans;
int lowbit(int x)
{
    return x&-x;
}
int getSum(int* s,int x,int o)
{
    int sum=0;
    while(x>o) {
        sum+=s[x];
        x-=lowbit(x);
    }
    return sum;
}
void update(int* s,int v,int x,int o)
{
    while(x<=o) {
        s[x]+=v;
        x+=lowbit(x);
    }
}
void build(int l,int r,int rt,int d)
{
    for(int i=l;i<=r;i++) {
        order[d][i]=order[d-1][i];
        tree[d][i]=0;
    }
    if(l==r) return;
    int m=(l+r)/2;
    build(l,m,rt<<1,d+1);
    build(m+1,r,rt<<1|1,d+1);
    sort(order[d]+l,order[d]+r+1);
}
void query(int l,int r,int x,int flag,int d,int L,int R,int rt)
{
    if(l>r)
        return;
    if(l<=L&&r>=R) {
        int k=lower_bound(order[d]+L,order[d]+R+1,x)-order[d];
        if(k>R||order[d][k]>x) {
            k--;
        }
        int u=getSum(tree[d],k,L-1);
        if(flag) {
            k=k-L+1;
            ans-=k-u;
        }
        else {
            int v=getSum(tree[d],R,L-1);
            v-=u;
            ans-=R-k-v;
        }
        return;
    }
    int m=(L+R)/2;
    if(l<=m){
        query(l,r,x,flag,d+1,L,m,rt<<1);
    }
    if(r>m) {
        query(l,r,x,flag,d+1,m+1,R,rt<<1|1);
    }
}
void Update(int l,int x,int d,int L,int R,int rt)
{
    if(l==L&&l==R) {
        update(tree[d],1,l,R);
        return;
    }
    int m=(L+R)/2;
    if(l<=m) {
        Update(l,x,d+1,L,m,rt<<1);
    }
    else {
        Update(l,x,d+1,m+1,R,rt<<1|1);
    }
    int k=lower_bound(order[d]+L,order[d]+R+1,x)-order[d];
    update(tree[d],1,k,R);
}
int main()
{
    int x;
    while(~scanf("%d%d",&n,&m)) {
        memset(tree[0],0,sizeof(tree[0]));
        ans=0;
        for(int i=1;i<=n;i++) {
            scanf("%d",&order[0][i]);
            pos[order[0][i]]=i;
            ans+=i-1-getSum(tree[0],order[0][i],0);
            update(tree[0],1,order[0][i],n);
        }
        build(1,n,1,1);
        for(int i=0;i<m;i++) {
            scanf("%d",&x);
            printf("%lld\n",ans);
            query(1,pos[x]-1,x,0,1,1,n,1);
            query(pos[x]+1,n,x,1,1,1,n,1);
            Update(pos[x],x,1,1,n,1);
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值