索引
学习
- fhq treap
复习
- 欧拉回路
STL神器
- 一些可能很常用的函数介绍(持续更新)
- replace()
- random_shuffle()
-
nth_element()
- find()
- set_union() 求并集
- set_intersection() 求交集
-
priority_queue是支持自定义比较函数的
奇技淫巧
- 两行vector 求逆序对
- 六行vector 过平衡树板子
fhq treap
/*
reference:
https://www.luogu.org/blog/yhzq/solution-p3369
https://fop_zz.coding.me/2018/03/15/treap/#P3165-%E6%9C%BA%E6%A2%B0%E8%87%82%E6%8E%92%E5%BA%8F
translation:
solution:
trigger:
note:
*
date:
2019.08.01
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;++i)
#define dwn(i,a,b) for(ll i=a;i>=b;--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
#define N 500001
int tot,siz[N],val[N],rnd[N],son[N][2];
int x,y,n,rt;
void upd(int x){siz[x]=1+siz[son[x][0]]+siz[son[x][1]];}
int new_node(int x){siz[++tot]=1;val[tot]=x;rnd[tot]=rand();return tot;}
void split(int now,int k,int &x,int &y){
if(!now)x=y=0;
else{
if(val[now]<=k)
x=now,split(son[now][1],k,son[x][1],y);
else
y=now,split(son[now][0],k,x,son[y][0]);
upd(now);
}
}
int merge(int x,int y){
if(!x || !y)return x^y;
if(rnd[x]<rnd[y]){
son[x][1]=merge(son[x][1],y);
upd(x);
return x;
}
else {
son[y][0]=merge(x,son[y][0]);
upd(y);
return y;
}
}
int kth(int x,int k){
while(1){
if(siz[son[x][0]]>=k)
x=son[x][0];
else if(siz[son[x][0]]+1==k)
return x;
else
k-=siz[son[x][0]]+1,x=son[x][1];
}
}
int main(){
#ifdef WIN32
freopen("fhq.txt","r",stdin);
#endif
//srand(time(0));
srand((unsigned)time(NULL));
rd(n);
rep(i,1,n){
int op,a;rd(op),rd(a);
if(op==1){
split(rt,a,x,y);
rt=merge(merge(x,new_node(a)),y);
}
if(op==2){
int z=0;
split(rt,a,x,z);
split(x,a-1,x,y);
y=merge(son[y][0],son[y][1]);//不能写成x
rt=merge(merge(x,y),z);
}
if(op==3){
split(rt,a-1,x,y);
printf("%d
",siz[x]+1);
rt=merge(x,y);
}
if(op==4)
printf("%d
",val[kth(rt,a)]);
if(op==5){
split(rt,a-1,x,y);
printf("%d
",val[kth(x,siz[x])]);
rt=merge(x,y);
}
if(op==6){
split(rt,a,x,y);
printf("%d
",val[kth(y,1)]);
rt=merge(x,y);
}
}
return 0;
}
vector 求逆序对
首先我们想一下冒泡排序的过程,我们不难发现,对于每一个元素,我们实际上是让他不停的和前面的元素比较,交换。
也正是因为这个过程决定了在冒泡排序的过程中:一个位置的数的前面的数一定是递增的(从小到大排的话)
那么我们在交换的时候,直接二分找到一个合适的位置,插入即可
这个很显然可以用平衡树Vector实现
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;++i)
#define dwn(i,a,b) for(ll i=a;i>=b;--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
int n,m,ans,a[100001];
vector<int>v;
int main(){
rd(n);
rep(i,1,n)rd(a[i]);
rep(i,1,n){
int now=upper_bound(v.begin(),v.end(),a[i])-v.begin();
ans=ans+i-now-1;
v.insert(v.begin()+now,a[i]);
}
printf("%d",ans);
return 0;
}
vector 求平衡树
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;++i)
#define dwn(i,a,b) for(ll i=a;i>=b;--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
vector<int>v;
int n,op,x;
int main(){
v.reserve(100001);
rd(n);
while(n--){
rd(op),rd(x);
if(op==1)v.insert(lower_bound(v.begin(),v.end(),x),x);
if(op==2)v.erase(lower_bound(v.begin(),v.end(),x));
if(op==3)printf("%d
",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
if(op==4)printf("%d
",v[x-1]);
if(op==5)printf("%d
",v[lower_bound(v.begin(),v.end(),x)-v.begin()-1]);
if(op==6)printf("%d
",v[upper_bound(v.begin(),v.end(),x)-v.begin()]);
}
return 0;
}
复习欧拉回路
性质:
*如果图中奇数度的顶点个数小于等于2,则一定存在欧拉回路
*在无向图中每个顶点的度都是偶数,则一定存在回路
*在有向图中,每个节点的入度等于出度,则存在回路
例题
- 瑞瑞的木棍
使用并查集维护经过点的个数
设x为成功合并的次数,n为点数
则整张图含欧拉路当且仅当x>=n−1且奇度数点为0或2
顺便提一下
pbds真是个好东西
一些可能很常用的函数介绍(持续更新)
replace
- replace(初始位置,结束位置,替换字符串);
find
- (母字符串).find(子字符串,起始位置)
如果没有设置起始位置默认为从头开始。如果返回-1的话表示该字符串中没有查询的字符串出现。qwq
当然,如果读入的时候往右移动了一位,记得起始位置也要变一变qwqwq
random_shuffle()
- random_shuffle(起始位置,结束位置)
将数组打乱。
nth_element
- nth_element(起始位置,所求位置,结束位置)
它的用法是nth_element(a+l,a+k,a+r)
这样它会使a这个数组中区间[l,r)内的第k小的元素处在第k个位置上(相对位置)
但是它并不保证其他元素有序!
不过根据网友的实验,貌似在vs上是有序的,不过在dev中是无序的
时间复杂度:O(n)
#include<bits/stdc++.h>
using namespace std;
int a[15]={0,100,200,500,700,300,400,100};
int main(){
nth_element(a+1,a+4,a+9);
for(int i=1;i<=8;++i)
printf("%d ", a[i]);
return 0;
}
时间复杂度为O(N),比所求数小的数都在这个数前面,比所求数大的数都在这个数后面,但是不保证有序。
最大的应用价值为求中位数
set_union() 求并集
set_intersection() 求交集
以下是程序演示
#include<bits/stdc++.h>
using namespace std;
int main(){
set<int>s1,s2,s3,s4;
s1.insert(1);
s1.insert(2);
s2.insert(2);
s2.insert(4);
set_union(s1.begin(),s1.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
set_intersection(s1.begin(),s1.end(),s2.begin(),s2.end(),inserter(s4,s4.begin()));
for(set<int>::iterator it=s3.begin();it!=s3.end();it++)
cout<<*it<<" ";
cout<<endl;
for(set<int>::iterator it=s4.begin();it!=s4.end();it++)
cout<<*it<<" ";
}
priority_queue支持自定义比较函数
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;++i)
#define dwn(i,a,b) for(ll i=a;i>=b;--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
#define mem(a,b) memset(a,b,sizeof(a))
const int n=5;
struct node{
int x,y;
node(){x=y=0;}
node(int a,int b){x=a;y=b;}
bool operator<(const node &a)const{
if(x!=a.x)return x>a.x;
return y<a.y;
}
};
priority_queue<node>q;
int a[15]={0,1,4,4,3,5};
int b[15]={0,2,1,2,3,4};
int main(){
rep(i,1,n)
q.push(node(a[i],b[i]));
while(q.size()!=0){
printf("%d %d
",q.top().x,q.top().y);
q.pop();
}
return 0;
}