洛谷P1975【国家集训队】排队

题目大意

给出\(n\)个数,每次交换两个数\(l,r\)之后维护逆序对数量。

题解

初始答案用归并排序求即可。

我们考虑交换的影响,

显然对于区间\([1,l)\)\((r,n]\),本次交换并不会对其贡献有什么影响。

对于\(l\)向右移之后,在区间\([l,r]\)中比\(l\)小的数的贡献消失了,新增了比\(l\)大的数的个数的贡献

\(r\)同理。

对于\(l,r\)本身,如果\(l\)的值大于\(r\),--\(ans\),否则++\(ans\)

于是我们需要一个数据结构,支持以下操作

区间查询比\(val\)小的数,

区间查询比\(val\)大的数,

单点修改。

老规矩,线段树套平衡树即可

献上丑陋的代码

/*
@Date    : 2019-07-21 10:03:17
@Author  : Adscn (adscn@qq.com)
@Link    : https://www.cnblogs.com/LLCSBlog
*/
#ifdef FASTER
#pragma GCC diagnostic error "-std=c++11"
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#endif
#include<bits/stdc++.h>
using namespace std;
#define IL inline
#define RG register
#define gi getint()
#define gc getchar()
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
IL int getint()
{
    RG int xi=0;
    RG char ch=gc;
    bool f=0;
    while(ch<'0'||ch>'9')ch=='-'?f=1:f,ch=gc;
    while(ch>='0'&&ch<='9')xi=(xi<<1)+(xi<<3)+ch-48,ch=gc;
    return f?-xi:xi;
}
template<typename T>
IL void pi(T k,char ch=0)
{
    if(k<0)k=-k,putchar('-');
    if(k>=10)pi(k/10,0);
    putchar(k%10+'0');
    if(ch)putchar(ch);
}
const int N=2e4+10;
class SplayTree{
private:
    struct node;
    typedef node* tree;
    struct node{
        tree ch[2],par;
        int siz,val,cnt;
        node(void){ch[0]=ch[1]=par=NULL,cnt=val=siz=0;}
        node(int v,tree p):par(p),val(v){ch[0]=ch[1]=NULL,cnt=siz=1;}
    }*root;
public:
    SplayTree(){root=NULL;}
    ~SplayTree(){entire_free(root);}
protected:
    inline void entire_free(tree x)
    {
        if(!x)return;
        entire_free(x->ch[0]),entire_free(x->ch[1]);
        delete x;
    }
    inline bool ws(tree x,tree p){return p?p->ch[1]==x:0;}
    inline int siz(tree x){return x?x->siz:0;}
    inline void connect(tree x,tree p,bool which)
    {
        x?(x->par=p):0,
        (p?p->ch[which]:root)=x;
    }
    inline void pushup(tree x){if(x)x->siz=siz(x->ch[0])+siz(x->ch[1])+x->cnt;}
    inline void rotate(tree x)
    {
        tree p=x->par,g=p->par;
        bool r=ws(x,p);
        connect(x,g,ws(p,g)),
        connect(x->ch[!r],p,r),
        connect(p,x,!r);
        pushup(p);
    }
    inline void Splay(tree x,tree y)
    {
        if(!x)return;
        register tree p,g;
        while(x->par!=y)
        {
            p=x->par,g=p->par;
            if(g!=y)rotate(ws(x,p)^ws(p,g)?x:p);
            rotate(x);
        }
        pushup(x);
    }
    inline void find(int val)
    {
        tree x=root;
        while(x&&x->ch[val>x->val]&&val!=x->val)x=x->ch[val>x->val];
//      if(x->val!=val){
//          cerr<<"Error : FIND : val:"<<val<<" does not exist!"<<endl;
//          return;
//      }
        Splay(x,NULL);
    }
public:
    inline void insert(int val)
    {
        if(!root){
            root=new node(val,NULL);
            return;
        }
        #define nxt (val>x->val)
        for(tree x=root;x;x=x->ch[nxt])
        {
            if(x->val==val)
            {
                ++x->cnt;
                Splay(x,NULL);
                return;
            }
            if(!x->ch[nxt])
            {
                x->ch[nxt]=new node(val,x);
                Splay(x->ch[nxt],NULL);
                return;
            }
        }
        #undef nxt
        return;
    }
    inline void remove(int val)
    {
        find(val);
        tree x=root;
        if(!x||x->val!=val)return;
//      cerr<<val<<endl;
/*      try{
            if(x==NULL)throw "empty";
            if(x->val!=val)throw "non-existent";
        }catch(const char *s){
            if(s=="empty")cerr<<"Error: REMOVE : Tree is empty"<<endl;
            if(s=="non-existent")cerr<<"Error: REMOVE : val doesn't exist"<<endl;
            return;
        }*/
        if(x->cnt>1)--x->cnt;
        else if(!x->ch[0])
        {
            connect(x->ch[1],NULL,0);
            delete x;
        }
        else{
            tree k=x->ch[0];
            while(k->ch[1])k=k->ch[1];
            Splay(k,x);
            connect(x->ch[1],k,1);
            connect(k,NULL,0);
            delete x;
        }
    }
    inline int rank_min(int x)
    {
        insert(x);
        assert(x==root->val);
        int ans=siz(root->ch[0]);
        remove(x);
        return ans;
    }
    inline int rank_max(int x)
    {
        insert(x);
        assert(x==root->val);
        int ans=siz(root->ch[1]);
        remove(x);
        return ans;
    }
}bt[N<<2];
void Insert(int rt,int l,int r,int pos,int val)
{
    bt[rt].insert(val);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)Insert(rt<<1,l,mid,pos,val);
    else Insert(rt<<1|1,mid+1,r,pos,val);
}
void Remove(int rt,int l,int r,int pos,int val)
{
    bt[rt].remove(val);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)Remove(rt<<1,l,mid,pos,val);
    else Remove(rt<<1|1,mid+1,r,pos,val);
}
inline int Rank_min(int rt,int l,int r,int ql,int qr,int val)
{
    if(ql<=l&&r<=qr)return bt[rt].rank_min(val);
    int ans=0,mid=(l+r)>>1;
    if(ql<=mid)ans+=Rank_min(rt<<1,l,mid,ql,qr,val);
    if(qr>mid) ans+=Rank_min(rt<<1|1,mid+1,r,ql,qr,val);
    return ans;
}
inline int Rank_max(int rt,int l,int r,int ql,int qr,int val)
{
    if(ql<=l&&r<=qr)return bt[rt].rank_max(val);
    int ans=0,mid=(l+r)>>1;
    if(ql<=mid)ans+=Rank_max(rt<<1,l,mid,ql,qr,val);
    if(qr>mid) ans+=Rank_max(rt<<1|1,mid+1,r,ql,qr,val);
    return ans;
}
int c[N];
int tmp[N],n;
int a[N],ans;
inline void Merge_sort(int L,int R)
{
    if(L==R)return;
    int mid=(L+R)>>1;
    Merge_sort(L,mid),Merge_sort(mid+1,R);
    int l=L,r=mid+1,t=L;
    while(l<=mid&&r<=R)
    {
        if(c[l]>c[r])ans+=mid-l+1,tmp[t++]=c[r++];
        else tmp[t++]=c[l++];
    }
    while(l<=mid)tmp[t++]=c[l++];
    while(r<=R)tmp[t++]=c[r++];
    for(int i=L;i<=R;++i)c[i]=tmp[i];
}
int main(void)
{
    #ifndef ONLINE_JUDGE
    File("file");
    #endif
    n=gi;
    for(int i=1;i<=n;++i)c[i]=a[i]=gi,Insert(1,1,n,i,a[i]);
    Merge_sort(1,n);
    pi(ans,'\n');
    int m=gi;
    while(m--)
    {
        int l=gi,r=gi;
        if(l>r)swap(l,r);
        ans+=Rank_max(1,1,n,l+1,r-1,a[l])-Rank_min(1,1,n,l+1,r-1,a[l]);
        ans+=Rank_min(1,1,n,l+1,r-1,a[r])-Rank_max(1,1,n,l+1,r-1,a[r]);
        if(a[l]>a[r])--ans;
        if(a[l]<a[r])++ans;
        pi(ans,'\n');
        Insert(1,1,n,l,a[r]);
        Insert(1,1,n,r,a[l]);
        Remove(1,1,n,l,a[l]);
        Remove(1,1,n,r,a[r]);
        swap(a[l],a[r]);
    }
    return 0;
}

转载于:https://www.cnblogs.com/LLCSBlog/p/11226667.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值