震惊!Vector两行代码求逆序对,六行代码过普通平衡树

Vector两行代码求逆序对

背景:济南集训Day7上午T2,出了一道逆序对的裸题,SB的我没看出是逆序对来,于是现场推了一个很刁钻的求逆序对的方法

首先我们想一下冒泡排序的过程,我们不难发现,对于每一个元素,我们实际上是让他不停的和前面的元素比较,交换。

也正是因为这个过程决定了在冒泡排序的过程中:一个位置的数的前面的数一定是递增的(从小到大排的话)

那么我们在交换的时候,直接二分找到一个合适的位置,插入即可

这个很显然可以用平衡树Vector实现

代码也非常短,

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<vector>
 4 using namespace std;
 5 int n,m,ans,a[100001];
 6 vector<int>v;
 7 int main()
 8 {
 9     scanf("%d",&n);
10     for(int i=1;i<=n;i++)    scanf("%d",&a[i]);
11     for(int i=1;i<=n;i++)
12     {
13         int now=upper_bound(v.begin(),v.end(),a[i])-v.begin();
14         ans=ans+i-now-1,v.insert(v.begin()+now,a[i]);
15     }
16     printf("%d",ans);
17     return 0;
18 }

 

update in 2017.12.16

补一发splay

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e6+10;
const int maxn=0x7fffff;
inline char nc()
{
    static char buf[MAXN],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    char c=nc();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=nc();}
    return x*f;
}
#define root tree[0].ch[1]
struct node
{
    int v,fa,ch[2],rec,sum;
};
node tree[MAXN];
int pointnum,tot;
int iden(int x){return tree[tree[x].fa].ch[0]==x?0:1;}
inline void connect(int x,int fa,int how){tree[x].fa=fa;tree[fa].ch[how]=x;}
inline void update(int x){tree[x].sum=tree[tree[x].ch[0]].sum+tree[tree[x].ch[1]].sum+tree[x].rec;}
inline void rotate(int x)
{
    int y=tree[x].fa;
    int R=tree[y].fa;
    int Rson=iden(y);
    int yson=iden(x);
    int b=tree[x].ch[yson^1];
    connect(b,y,yson);
    connect(y,x,yson^1);
    connect(x,R,Rson);
    update(y);update(x);
}
void splay(int pos,int to)// 把编号为pos的节点旋转到编号为to的节点 
{
    to=tree[to].fa;
    while(tree[pos].fa!=to)
    {
        if(tree[tree[pos].fa].fa==to)    rotate(pos);
        else if(iden(tree[pos].fa)==iden(pos))    rotate(tree[pos].fa),rotate(pos);
        else    rotate(pos),rotate(pos);
    }
}
inline int newpoint(int v,int fa)//
{
    tree[++tot].fa=fa;
    tree[tot].v=v;
    tree[tot].sum=tree[tot].rec=1;
    return tot;
}
inline void dele(int x)
{
    tree[x].ch[0]=tree[x].ch[1]=0;
    if(x==tot)  tot--;
}
int find(int v)
{
    int now=root;
    while(1)
    {
        if(tree[now].v==v)   {splay(now,root);return now;}
        int nxt=v<tree[now].v?0:1;
        if(!tree[now].ch[nxt])return 0;
        now=tree[now].ch[nxt];
    }
}
int build(int v)
{
    pointnum++;
    if(tot==0){root=1;newpoint(v,0);}
    else
    {
        int now=root;
        while(1)
        {
            tree[now].sum++;
            if(tree[now].v==v){tree[now].rec++;return now;}//出现过
            int nxt=v<tree[now].v?0:1;
            if(!tree[now].ch[nxt])
            {
                newpoint(v,now);
                tree[now].ch[nxt]=tot;
                return tot;
            }
            now=tree[now].ch[nxt];
        }
    }
    return 0;
}
inline void insert(int v)
{
    int p=build(v);//p代表插到了哪里
    splay(p,root);
}
void pop(int v)
{
    int deal=find(v);
    if(!deal)   return ;
    pointnum--;
    if(tree[deal].rec>1){tree[deal].rec--;tree[deal].sum--;return ;}
    if(!tree[deal].ch[0])    root=tree[deal].ch[1],tree[root].fa=0;
    else
    {
        int le=tree[deal].ch[0];
        while(tree[le].ch[1])    le=tree[le].ch[1];
        splay(le,tree[deal].ch[0]);
        int ri=tree[deal].ch[1];
        connect(ri,le,1);connect(le,0,1);
        update(le);
    }
    dele(deal);
}
int rank(int v)// 查询值为v的数的排名 
{
    int ans=0,now=root;
    while(1)
    {
        if(tree[now].v==v)    return ans+tree[tree[now].ch[0]].sum+1;
        if(now==0)  return 0;
        if(v<tree[now].v)    now=tree[now].ch[0];
        else                 ans+=tree[tree[now].ch[0]].sum+tree[now].rec,now=tree[now].ch[1];
    }
    if(now)    splay(now,root);
    return 0;
}
int arank(int x)//查询排名为x的数是什么 
{
    int now=root;
    while(1)
    {
        int used=tree[now].sum-tree[tree[now].ch[1]].sum;
        if(x>tree[tree[now].ch[0]].sum&&x<=used)    break;
        if(x<used)    now=tree[now].ch[0];
        else    x=x-used,now=tree[now].ch[1];
    }
    splay(now,root);
    return tree[now].v;
}
int lower(int v)// 小于v的最大值 
{
    int now=root;
    int ans=-maxn;
    while(now)
    {
        if(tree[now].v<v&&tree[now].v>ans)    ans=tree[now].v;
        if(v>tree[now].v)    now=tree[now].ch[1];
        else    now=tree[now].ch[0];
    }
    return ans;
}
int upper(int v)
{
    int now=root;
    int ans=maxn;
    while(now)
    {
        if(tree[now].v>v&&tree[now].v<ans)    ans=tree[now].v;
        if(v<tree[now].v)    now=tree[now].ch[0];
        else    now=tree[now].ch[1];
    }
    return ans;
}
int a[MAXN],n,ans=0;
int main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else
    #endif
    n=read();
    for(int i=1;i<=n;i++)    a[i]=read();
    for(int i=1;i<=n;i++)
    {
        insert(a[i]);
        int now=rank(a[i]);
        if(i==1) continue;
        ans=ans+i-now;
    }
    printf("%d",ans);
} 
View Code

 

 

Vector六行代码过平衡树

这个参考了一下黄学长的博客,不过我没有用迭代器实现

顺便精简了一下代码

代码应该比较容易懂,就不细讲了

 1 #include<cstdio>
 2 #include<vector>
 3 #include<algorithm>
 4 using namespace std;
 5 vector<int>v;
 6 int n,opt,x;
 7 int main()
 8 {
 9     v.reserve(100001);
10     scanf("%d",&n);
11     while(n--)
12     {
13         scanf("%d%d",&opt,&x);
14         if(opt==1)    v.insert(lower_bound(v.begin(),v.end(),x),x);
15         if(opt==2)    v.erase (lower_bound(v.begin(),v.end(),x));
16         if(opt==3)    printf("%d\n",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
17         if(opt==4)    printf("%d\n",v[x-1]);
18         if(opt==5)    printf("%d\n",v[lower_bound(v.begin(),v.end(),x)-v.begin()-1]);
19         if(opt==6)    printf("%d\n",v[upper_bound(v.begin(),v.end(),x)-v.begin()]);
20     }
21     return 0;
22 }

 

总的来说

Vector是个好东西,

试想一下如果未来每场考试都开O2的话,

数组这个东西会不会就消失了?Σ( ° △ °|||)︴

 

posted @ 2017-11-05 20:23 自为风月马前卒 阅读(...) 评论(...) 编辑 收藏

Contact with me

……