zoukankan      html  css  js  c++  java
  • 震惊!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
    ",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
    17         if(opt==4)    printf("%d
    ",v[x-1]);
    18         if(opt==5)    printf("%d
    ",v[lower_bound(v.begin(),v.end(),x)-v.begin()-1]);
    19         if(opt==6)    printf("%d
    ",v[upper_bound(v.begin(),v.end(),x)-v.begin()]);
    20     }
    21     return 0;
    22 }

    总的来说

    Vector是个好东西,

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

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

  • 相关阅读:
    #网络流,最小割#洛谷 1344 [USACO4.4]追查坏牛奶Pollutant Control
    #线段树,倒序#CF356A Knight Tournament
    #错排,高精度#洛谷 3182 [HAOI2016]放棋子
    #KMP,dp#洛谷 3426 [POI2005]SZA-Template
    #差分约束系统,Spfa,SLF优化#Hdu 3666 THE MATRIX PROBLEM
    #min_max容斥#Hdu 4336 Card Collector
    #组合计数,卢卡斯定理#D 三元组
    #计数,记忆化搜索#C 连边方案
    #区间dp,离散#D 弱者对决
    #dp#C 公共子序列
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/7788554.html
Copyright © 2011-2022 走看看