震惊!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,…, ...
随机推荐
- Shadow Copying导致ASP.NET应用启动很慢的解决办法
What's Shadow Copying? 我们安装一个应用程序并启动后,我们是无法更新应用程序安装目录中程序集文件的.如果强制替换会提示文件正在使用,如下图所示. 那你可能会问,为什么会无法更新呢 ...
- spring的定时器
一:基于xml配置的方式 1:编写普通的pojo 类 package com.aflyun.web.task; import org.springframework.stereotype.Compon ...
- python glob的安装和使用
基本概念 glob是python自己带的一个文件操作相关模块,用它可以查找符合自己目的的文件,类似于Windows下的文件搜索,支持通配符操作.*,?,[]这三个通配符,*代表0个或多个字符,?代表一 ...
- Go语言的一些使用心得
序 起初一直使用的Python,到了18年下半年由于业务需求而接触了Golang,从开始学习到现在的快半年里,也用Golang写了些代码,公司产品和业余写的都有,今天就写点Golang相关的总结或者感 ...
- Python 使用图灵机器人实现微信聊天功能
首先需要去图灵官网创建一个属于自己的机器人然后得到apikey. 一.自动与指定好友聊天 # -*- coding: utf-8 -*- """ Created at 2 ...
- Spring中你可能不知道的事(二)
在上一节中,我介绍了Spring中极为重要的BeanPostProcessor BeanFactoryPostProcessor Import ImportSelector,还介绍了一些其他的零碎知识 ...
- python批量启动多线程
还未了解多线程的请查看博文 python3多线程趣味详解 python3多线程趣味详解 只是介绍了 python 多线程的使用,对于批量启动线程来说有些不适用,于是出现如下方法: 建立一个线程池,并将 ...
- Lucene 08 - 什么是Lucene的相关度排序 + Java API调整相关度
目录 1 什么是相关度 2 相关度评分 3 相关度设置 3.1 更改相关度的需求 3.2 实现需求-设置广告 1 什么是相关度 概念: 相关度指两个事物之间的关联关系(相关性). Lucene中指的是 ...
- Lucene 05 - 使用Lucene的Java API实现分页查询
目录 1 Lucene的分页查询 2 代码示例 3 分页查询结果 1 Lucene的分页查询 搜索内容过多时, 需要考虑分页显示, 像这样: 说明: Lucene的分页查询是在内存中实现的. 2 代码 ...
- 使用mpvue开发小程序教程(四)
在上一章节中,我们将vue-cli命令行工具生成的代码骨架中的src目录清理了一遍,然后从头开始配置和编写了一个可以运行的小程序页面,算是正真走上了使用mpvue开发小程序的第一步.今天我们将进一步来 ...