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

acm_cxlove發表於2013-04-01

轉載請註明出處,謝謝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;
}


相關文章