震惊!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,…, ...
随机推荐
- input type=passoord 密码框的明密文(显示和隐藏) 显示
最近在写一个新的项目,从头开始写,所以就要从注册登录开始做起.以前写登录注册模块的时候,无外乎给input框一个type=”password”就可以了,近期因为要涉及到显示隐藏状态的切换. 样式代码如 ...
- [Swift]LeetCode314. 二叉树的竖直遍历 $ Binary Tree Vertical Order Traversal
Given a binary tree, return the vertical order traversal of its nodes' values. (ie, from top to bott ...
- [Swift]LeetCode556. 下一个更大元素 III | Next Greater Element III
Given a positive 32-bit integer n, you need to find the smallest 32-bit integer which has exactly th ...
- [Swift]LeetCode563. 二叉树的坡度 | Binary Tree Tilt
Given a binary tree, return the tilt of the whole tree. The tilt of a tree node is defined as the ab ...
- [Swift]LeetCode932. 漂亮数组 | Beautiful Array
For some fixed N, an array A is beautiful if it is a permutation of the integers 1, 2, ..., N, such ...
- javascript时间戳与日期格式之间的互转
1. 将时间戳转换成日期格式 // 简单的一句代码 var date = new Date(时间戳); //获取一个时间对象 /** 1. 下面是获取时间日期的方法,需要什么样的格式自己拼接起来就好了 ...
- VMware虚拟机安装Linux系统
许多新手连 Windows 的安装都不太熟悉,更别提 Linux 的安装了:即使安装成功了,也有可能破坏现有的 Windows 系统,比如导致硬盘数据丢失.Windows 无法开机等.所以一直以来,安 ...
- VMware Workstation下安装Linux
下载VMware Workstation thunder://QUFodHRwczovL2Rvd25sb2FkMy52bXdhcmUuY29tL3NvZnR3YXJlL3drc3QvZmlsZS9WT ...
- 受到 1 万点暴击,二狗子被 DDoS 攻击的惨痛经历
二狗子的遭遇 “好消息,好消息,免费 DDoS 攻击软件上线了,性感黑客在线攻击,帮您攻克所有商业难题.”二狗子不知道在看着什么网站,新买的 Mac 中发出热闹的声音. 二狗子想知道“DDoS 是什么 ...
- Java核心技术及面试指南:视频列表
如下是本书相关内容的视频列表,会动态更新 第一章 1 视频1.1 JDK和JRE和JVM的区别,安装Java开发环境 1.1.1 第2页 2 视频1.2 编写第一个HelloWorld程序 ...