1. 程式人生 > >luogu1975 [國家集訓隊]排隊

luogu1975 [國家集訓隊]排隊

註意 amp etc upd 都是 樹狀數組 namespace con lsh

思路

序列中
|i | 1| 2| 3| 4| 5| 6| 7| 8| 9| 10|
|----|--|--|--|--|--|--|--|--|--|--|
|a[i]| a| b| c| L| d| e| f| R| g| h|
現逆序對為ans,要交換L,R
\([1,3],[9,10]\)這兩段區間的都不會被他倆影響 (因為L,R和他們相對位置沒變啦)
所以現在我們只需要考慮區間\([4,8]\)就好,其他的不考慮在內
一個數對一個區間產生逆序對的貢獻為
① 前面大於他的數的個數 (在區間前面)
② 後面小於他的數的個數 (在區間後面)
因為\(L,R\)之間的區間3,6是不變的(廢話)

\(L,R\)又在區間兩端
那麽很顯然的
\(ans=ans-(L對區間zz的貢獻②)+(L對區間zz的貢獻①)-(R對區間zz的貢獻①)+(R對區間zz的貢獻②)\)
那區間內的貢獻咋求啊?
定義不是很明確了嗎 就是區間大於x或者小於的個數
\(=>ans-(區間zz內小於L的個數)+(區間zz內大於L的個數)-(區間zz內大於R的個數)+(區間zz內小於R的個數)\)(註意,相等的沒有任何貢獻)
無腦數據結構唄
隨便來個帶修主席樹 (樹狀數組套線段樹)
復雜度\(nlog^{2}n\)
但常數巨大,更新一次ans要詢問8次

錯誤

都是些zz錯誤
n寫成len
特盤忘記輸出ans

代碼

//天蒼蒼,野茫茫,代碼怎麽這麽長
#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=1e5+7;
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
int n,m,ans,len,rt[maxn],a[maxn],lsh[maxn],cnt;
int thu[maxn];
struct node {
    int ch[2],siz;
}e[maxn*30];
void build(int &now,int old,int l,int r,int k) {
     now=++cnt;
     e[now]=e[old];
     e[now].siz++;
     if(l==r) return;
     int mid=(l+r)>>1;
     if(k<=mid) build(e[now].ch[0],e[old].ch[0],l,mid,k);
     else build(e[now].ch[1],e[old].ch[1],mid+1,r,k);
}
void modify(int &now,int l,int r,int k,int gs) {
    if(!now) now=++cnt;
    e[now].siz+=gs;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(k<=mid) modify(e[now].ch[0],l,mid,k,gs);
    else modify(e[now].ch[1],mid+1,r,k,gs);
}
int query1(int now,int l,int r,int k) { //小於mid的數 
    if(l>=k) return 0;
    if(r<k) {
        int tot=e[now].siz;
        FOR(i,1,thu[0]) tot+=e[thu[i]].siz;
        return tot;
    }
    int mid=(l+r)>>1;
    if(k<=mid) {
        FOR(i,1,thu[0]) thu[i]=e[thu[i]].ch[0];
        return query1(e[now].ch[0],l,mid,k);    
    } else {
        int tot=e[e[now].ch[0]].siz;
        FOR(i,1,thu[0]) tot+=e[e[thu[i]].ch[0]].siz;
        FOR(i,1,thu[0]) thu[i]=e[thu[i]].ch[1];
        return tot+query1(e[now].ch[1],mid+1,r,k);  
    }
}
int query2(int now,int l,int r,int k) { //大於mid的數 
    if(r<=k) return 0;
    if(l>k) {
        int tot=e[now].siz;
        FOR(i,1,thu[0]) tot+=e[thu[i]].siz;
        return tot;
    }
    int mid=(l+r)>>1;
    if(k<=mid) {
        int tot=e[e[now].ch[1]].siz;
        FOR(i,1,thu[0]) tot+=e[e[thu[i]].ch[1]].siz;
        FOR(i,1,thu[0]) thu[i]=e[thu[i]].ch[0];
        return tot+query2(e[now].ch[0],l,mid,k);
    } else {
        FOR(i,1,thu[0]) thu[i]=e[thu[i]].ch[1];
        return query2(e[now].ch[1],mid+1,r,k);  
    }
}
int solve(int l,int r,int k,int pd) {//區間內小於(或小於)k的個數
    int tmp=0;
    
    thu[0]=0;
    for(int i=r;i>=1;i-=(i&-i)) thu[++thu[0]]=rt[i+n];
    tmp+=pd ? query1(rt[r],1,len,k) : query2(rt[r],1,len,k);
    
    thu[0]=0;
    for(int i=l-1;i>=1;i-=(i&-i)) thu[++thu[0]]=rt[i+n];
    tmp-=pd ? query1(rt[l-1],1,len,k) : query2(rt[l-1],1,len,k);
    
    return tmp;
}
namespace get_init_ans {
    int sum[maxn];
    void BIT_modify(int x) {
        for(int i=x;i<=n;i+=(i&-i)) sum[i]++;
    }
    int BIT_query(int x) {
        int tot=0;
        for(int i=x;i>=1;i-=(i&-i)) tot+=sum[i];
        return tot;
    } 
    void get_ans() {
        for(int i=1;i<=n;++i) {
            BIT_modify(a[i]); 
            ans+=i-BIT_query(a[i]);
        }
    }
}
using namespace get_init_ans; 
int main() {
    //read
    n=read();
    FOR(i,1,n) a[i]=lsh[i]=read();
    //lsh and init
    sort(lsh+1,lsh+1+n);
    len=unique(lsh+1,lsh+1+n)-lsh-1;
    FOR(i,1,n) {
        a[i]=lower_bound(lsh+1,lsh+1+len,a[i])-lsh; 
        build(rt[i],rt[i-1],1,len,a[i]);
    }
    //get_ans
    get_ans();
    cout<<ans<<"\n";
    //work
    m=read();
    FOR(i_ak_ioi,1,m) {
        int x=read(),y=read(),l,l1=0,l2=0,r,r1=0,r2=0;
        if(a[x]==a[y]) {
            cout<<ans<<"\n";
            continue;   
        }
        if(x>y) swap(x,y);
        //query
        l=x+1,r=y-1;
        if(l<=r) {
            l2=solve(l,r,a[x],1);
            l1=solve(l,r,a[x],0);
            r2=solve(l,r,a[y],1);
            r1=solve(l,r,a[y],0);
        }
        //update
        ans=ans-l2+l1-r1+r2+(a[x]<a[y] ? 1 : -1);
        cout<<ans<<"\n";
        //update
        for(int i=x;i<=n;i+=(i&-i)) {
            modify(rt[i+n],1,len,a[x],-1);
            modify(rt[i+n],1,len,a[y],1);
        }
        for(int i=y;i<=n;i+=(i&-i)) {
            modify(rt[i+n],1,len,a[y],-1);
            modify(rt[i+n],1,len,a[x],1);   
        }
        swap(a[x],a[y]);
    }
    return 0;
}

luogu1975 [國家集訓隊]排隊