震惊!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); }
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的话,
数组这个东西会不会就消失了?Σ( ° △ °|||)︴
作者:自为风月马前卒
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。