8.1

索引

学习

  • 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\n",siz[x]+1);
            rt=merge(x,y);
        }
        if(op==4)  
            printf("%d\n",val[kth(rt,a)]);
        if(op==5){
            split(rt,a-1,x,y);
            printf("%d\n",val[kth(x,siz[x])]);
            rt=merge(x,y);
        }
        if(op==6){
            split(rt,a,x,y);
            printf("%d\n",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\n",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
        if(op==4)printf("%d\n",v[x-1]);
        if(op==5)printf("%d\n",v[lower_bound(v.begin(),v.end(),x)-v.begin()-1]);
        if(op==6)printf("%d\n",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\n",q.top().x,q.top().y);
        q.pop();
    }
    return 0;
}
知识兔
计算机