震惊!Vector两行代码求逆序对,六行代码过普通平衡树
Vector两行代码求逆序对
背景:济南集训Day7上午T2,出了一道逆序对的裸题,SB的我没看出是逆序对来,于是现场推了一个很刁钻的求逆序对的方法
首先我们想一下冒泡排序的过程,我们不难发现,对于每一个元素,我们实际上是让他不停的和前面的元素比较,交换。
也正是因为这个过程决定了在冒泡排序的过程中:一个位置的数的前面的数一定是递增的(从小到大排的话)
那么我们在交换的时候,直接二分找到一个合适的位置,插入即可
这个很显然可以用平衡树Vector实现
代码也非常短,
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int n,m,ans,a[];
vector<int>v;
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
for(int i=;i<=n;i++)
{
int now=upper_bound(v.begin(),v.end(),a[i])-v.begin();
ans=ans+i-now-,v.insert(v.begin()+now,a[i]);
}
printf("%d",ans);
return ;
}
update in 2017.12.16
补一发splay
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e6+;
const int maxn=0x7fffff;
inline char nc()
{
static char buf[MAXN],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
char c=nc();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=nc();}
while(c>=''&&c<=''){x=x*+c-'';c=nc();}
return x*f;
}
#define root tree[0].ch[1]
struct node
{
int v,fa,ch[],rec,sum;
};
node tree[MAXN];
int pointnum,tot;
int iden(int x){return tree[tree[x].fa].ch[]==x?:;}
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[]].sum+tree[tree[x].ch[]].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^];
connect(b,y,yson);
connect(y,x,yson^);
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=;
return tot;
}
inline void dele(int x)
{
tree[x].ch[]=tree[x].ch[]=;
if(x==tot) tot--;
}
int find(int v)
{
int now=root;
while()
{
if(tree[now].v==v) {splay(now,root);return now;}
int nxt=v<tree[now].v?:;
if(!tree[now].ch[nxt])return ;
now=tree[now].ch[nxt];
}
}
int build(int v)
{
pointnum++;
if(tot==){root=;newpoint(v,);}
else
{
int now=root;
while()
{
tree[now].sum++;
if(tree[now].v==v){tree[now].rec++;return now;}//出现过
int nxt=v<tree[now].v?:;
if(!tree[now].ch[nxt])
{
newpoint(v,now);
tree[now].ch[nxt]=tot;
return tot;
}
now=tree[now].ch[nxt];
}
}
return ;
}
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>){tree[deal].rec--;tree[deal].sum--;return ;}
if(!tree[deal].ch[]) root=tree[deal].ch[],tree[root].fa=;
else
{
int le=tree[deal].ch[];
while(tree[le].ch[]) le=tree[le].ch[];
splay(le,tree[deal].ch[]);
int ri=tree[deal].ch[];
connect(ri,le,);connect(le,,);
update(le);
}
dele(deal);
}
int rank(int v)// 查询值为v的数的排名
{
int ans=,now=root;
while()
{
if(tree[now].v==v) return ans+tree[tree[now].ch[]].sum+;
if(now==) return ;
if(v<tree[now].v) now=tree[now].ch[];
else ans+=tree[tree[now].ch[]].sum+tree[now].rec,now=tree[now].ch[];
}
if(now) splay(now,root);
return ;
}
int arank(int x)//查询排名为x的数是什么
{
int now=root;
while()
{
int used=tree[now].sum-tree[tree[now].ch[]].sum;
if(x>tree[tree[now].ch[]].sum&&x<=used) break;
if(x<used) now=tree[now].ch[];
else x=x-used,now=tree[now].ch[];
}
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[];
else now=tree[now].ch[];
}
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[];
else now=tree[now].ch[];
}
return ans;
}
int a[MAXN],n,ans=;
int main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
#else
#endif
n=read();
for(int i=;i<=n;i++) a[i]=read();
for(int i=;i<=n;i++)
{
insert(a[i]);
int now=rank(a[i]);
if(i==) continue;
ans=ans+i-now;
}
printf("%d",ans);
}
Vector六行代码过平衡树
这个参考了一下黄学长的博客,不过我没有用迭代器实现
顺便精简了一下代码
代码应该比较容易懂,就不细讲了
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
vector<int>v;
int n,opt,x;
int main()
{
v.reserve();
scanf("%d",&n);
while(n--)
{
scanf("%d%d",&opt,&x);
if(opt==) v.insert(lower_bound(v.begin(),v.end(),x),x);
if(opt==) v.erase (lower_bound(v.begin(),v.end(),x));
if(opt==) printf("%d\n",lower_bound(v.begin(),v.end(),x)-v.begin()+);
if(opt==) printf("%d\n",v[x-]);
if(opt==) printf("%d\n",v[lower_bound(v.begin(),v.end(),x)-v.begin()-]);
if(opt==) printf("%d\n",v[upper_bound(v.begin(),v.end(),x)-v.begin()]);
}
return ;
}
总的来说
Vector是个好东西,
试想一下如果未来每场考试都开O2的话,
数组这个东西会不会就消失了?Σ( ° △ °|||)︴
震惊!Vector两行代码求逆序对,六行代码过普通平衡树的更多相关文章
- POJ-2299 Ultra-QuickSort---树状数组求逆序对+离散化
题目链接: https://vjudge.net/problem/POJ-2299 题目大意: 本题要求对于给定的无序数组,求出经过最少多少次相邻元素的交换之后,可以使数组从小到大有序. 两个数(a, ...
- 用归并排序或树状数组求逆序对数量 poj2299
题目链接:https://vjudge.net/problem/POJ-2299 推荐讲解树状数组的博客:https://blog.csdn.net/int64ago/article/details/ ...
- POJ 2299 Ultra-QuickSort 离散化加树状数组求逆序对
http://poj.org/problem?id=2299 题意:求逆序对 题解:用树状数组.每读入一个数x,另a[x]=1.那么a数列的前缀和s[x]即为x前面(或者说,再x之前读入)小于x的个数 ...
- 4163 hzwer与逆序对 (codevs + 权值线段树 + 求逆序对)
题目链接:http://codevs.cn/problem/4163/ 题目:
- 归并排序+归并排序求逆序对(例题P1908)
归并排序(merge sort) 顾名思义,这是一种排序算法,时间复杂度为O(nlogn),时间复杂度上和快排一样 归并排序是分治思想的应用,我们先将n个数不断地二分,最后得到n个长度为1的区间,显然 ...
- codeforces 540E 离散化技巧+线段树/树状数组求逆序对
传送门:https://codeforces.com/contest/540/problem/E 题意: 有一段无限长的序列,有n次交换,每次将u位置的元素和v位置的元素交换,问n次交换后这个序列的逆 ...
- 2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)
2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对) https://www.luogu.com.cn/problem/P5041 题意: 给一个字符串 \(S\) ,每 ...
- HDU 3743 Frosh Week(归并排序求逆序对)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3743 题目意思就是给你一个长为n的序列,让你求逆序对.我用的是归并排序来求的.归并排序有一个合并的过程 ...
- AC日记——codevs 1688 求逆序对
1688 求逆序对 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 给定一个序列a1,a2,…, ...
随机推荐
- VIM批量缩进
方法一 1.按 ctrl + shif + ; 进入底行模式 2.将所要批量缩进的行号写上,按照格式:“行号1,行号2>”输入命令,如要将4至11行批量缩进一个tab值,则命令为“4,11&g ...
- Android APK 瘦身 - JOOX Music项目实战
导语 JOOX Music是腾讯海外布局的一个音乐产品,2014年发布以来已经成为5个国家和地区排名第一的音乐App.东南亚是JOOX Music的主要发行地区,由于JOOX Music所面对的市场存 ...
- 理解Golang哈希表Map的元素
目录 概述 哈希函数 冲突解决 初始化 结构体 字面量 运行时 操作 访问 写入 扩容 删除 总结 在上一节中我们介绍了 数组和切片的实现原理,这一节会介绍 Golang 中的另一个集合元素 - 哈希 ...
- [Swift]LeetCode179. 最大数 | Largest Number
Given a list of non negative integers, arrange them such that they form the largest number. Example ...
- [Swift]LeetCode358. 按距离为k隔离重排字符串 $ Rearrange String k Distance Apart
Given a non-empty string str and an integer k, rearrange the string such that the same characters ar ...
- redis 主从配置,主从切换
只需修改从配置文件 # slaveof <masterip> <masterport> slaveof 127.0.0.1 6379 # masterauth <mast ...
- Linux中FTP远程传输,SSH远程连接,以及SCP远程拷贝
常用服务器ftp.ssh 1. Linux常用服务器构建-ftp服务器 ftp服务器 FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”. 用于 ...
- 为什么说Java中只有值传递
本文转载自公众号 Hollis 对于初学者来说,要想把这个问题回答正确,是比较难的.在第二天整理答案的时候,我发现我竟然无法通过简单的语言把这个事情描述的很容易理解,遗憾的是,我也没有在网上找到哪篇文 ...
- 【Kafka专栏】-Kafka从初始到搭建到应用
一.前述 Kafka是一个分布式的消息队列系统(Message Queue). kafka集群有多个Broker服务器组成,每个类型的消息被定义为topic. 同一topic内部的消息按照一定的key ...
- 在.net core上使用Entity FramWork(Db first)
在.net core中不可以向往常一样去直接可视化创建EF了,那我们可以通过命令安装 其依赖项有 Install-package Microsoft.EntityFrameworkCore Insta ...