震驚!Vector兩行程式碼求逆序對,六行程式碼過普通平衡樹

自為風月馬前卒發表於2017-11-05

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的話,

陣列這個東西會不會就消失了?Σ( ° △ °|||)︴

 

相關文章