luogu1975 [国家集训队]排队

思路

序列中
|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;
}
全部评论

相关推荐

10-15 10:57
已编辑
武昌理工学院 FPGA工程师
狠赚笔第一人:老哥学院本没实习还想拿13k学Java狠赚笔呢
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务