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的話,
陣列這個東西會不會就消失了?Σ( ° △ °|||)︴