CF 220E Little Elephant and Inversions(主席树+two points)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题目:给出个序列,问有多少个二元组(i,j)满足a1a2...alarar + 1... an 逆序对数不超过K
显然的一个问题是如果(i,j)满足,那么(i,j+r)  r>=0肯定满足
所以枚举左端点,维护右端点,典型的two points。
然后就是更新整个区间的逆序对数了。
删除一个数,或者添加一个数需要得增加或者减少的逆序对数,最好有当时的序列情况。
典型的就是可持久化线段树。
排序离散化后,从前往后,以及从后往前分别建立主席树,就是维护前缀和后缀。
然后就是two points过程了。更新的时候注意细节就行了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define lowbit(i) (i&(-i))
#define LL long long 
using namespace std;
const int N=100005;
const int M=5000000;
int n,m,a[N];
LL k;
vector<int>v;
struct persistent_tree{
    int lson[M],rson[M],c[M],T[M];
    int tot,m;
    void Init(int t,int _m){
        tot=0;m=_m;
        T[t]=bulid(1,m);
    }
    int bulid(int l,int r){
        int root=tot++;
        c[root]=0;
        if(l!=r){
            int m=(l+r)>>1;
            lson[root]=bulid(l,m);
            rson[root]=bulid(m+1,r);
        }
        return root;
    }
    int update(int root,int pos,int val){
        int newroot=tot++,tmp=newroot;
        c[newroot]=c[root]+val;
        int l=1,r=m;
        while(l<r){
            int mid=(l+r)>>1;
            if(pos<=mid){
                rson[newroot]=rson[root];
                lson[newroot]=tot++;
                newroot=lson[newroot];
                root=lson[root];
                r=mid;
            }
            else{
                lson[newroot]=lson[root];
                rson[newroot]=tot++;
                newroot=rson[newroot];
                root=rson[root];
                l=mid+1;
            }
            c[newroot]=c[root]+val;
        }
        return tmp;
    }
    int query(int root,int l,int r,int L,int R){
        if(R<L) return 0;
        if(l==L&&r==R)
            return c[root];
        int m=(l+r)>>1;
        if(R<=m) return query(lson[root],l,m,L,R);
        else if(L>m) return query(rson[root],m+1,r,L,R);
        else return query(lson[root],l,m,L,m)+query(rson[root],m+1,r,m+1,R);
    }
    void insert(int now,int old,int pos,int val){
        T[now]=update(T[old],pos,val);
    }
}pre,suf;
int main(){
    cin>>n>>k;
    v.push_back(-1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        v.push_back(a[i]);
    }
    sort(v.begin(),v.end());
    v.resize(unique(v.begin(),v.end())-v.begin());
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin();
    m=v.size()-1;
    pre.Init(0,m);
    suf.Init(m+1,m);
    for(int i=1;i<=n;i++) 
        pre.insert(i,i-1,a[i],1);
    for(int i=n;i>=1;i--) 
        suf.insert(i,i+1,a[i],1);
    LL cur=0,ans=0;
    for(int i=1;i<=n;i++)
        cur+=(LL)pre.query(pre.T[i],1,m,a[i]+1,m);
    //cur为初始状态下的逆序对数
    for(int i=1,j=2;i<=n;i++){
        while(j<=n&&cur>k){
            //将j点删除,便是找到[1,i]中比j大的,[j+1]中比j小的
            cur-=(LL)pre.query(pre.T[i],1,m,a[j]+1,m);
            cur-=(LL)suf.query(suf.T[j],1,m,1,a[j]-1);
            j++;
        }
        ans+=n-j+1;
        if(j==i+1){
            //始终保持j>i,删除j
            cur-=(LL)pre.query(pre.T[i],1,m,a[j]+1,m);
            cur-=(LL)suf.query(suf.T[j],1,m,1,a[j]-1);
            j++;
        }
        //恢复i+1
        //便是找到[1,i]中比i+1大的,[j,m]中比i+1小的
        cur+=(LL)pre.query(pre.T[i],1,m,a[i+1]+1,m);
        cur+=(LL)suf.query(suf.T[j],1,m,1,a[i+1]-1);
    }
    cout<<ans<<endl;
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值