奇技淫巧and板子

本文将记录一些奇技淫巧和板子(最基础的也有),先从今天开始写,之前的找个时间再补上code

求第\(k\)大的数

应用快速排序思想(\(O(n)\)),日常都是\(O(nlogn)\)
基于快排的思想,在每一层递归中,随机选取一个数作基准时,统计出大于基准值的数的个数\(cnt\),若是\(k<=cnt\)就在左半段(比基准数大)中寻找第\(k\)大的数,反之则在右半段寻找第\(k-cnt\)大的数排序

复杂度证实:递归

由于每次只进入了左右两段的任意一个,则在平均状况之下复杂度为:\(n+\frac{n}{2}+\frac{n}{3}+.....+1=O(n)\)it

求长度不小于L的子段使之和最大

ST表

预处理class

void st_prework() {
    for(int i=1; i<=n; ++i) f[i][0]=a[i];
    for(int j=1; j<=21; ++j)
        for(int i=1; i+(1<<j)-1<=n; ++i)
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}

查询基础

int query(int l,int r) {
    int res=-9999;
    int k=0;
    while((1<<(k+1)<=r-l+1)) k++;
    res=max(f[l][k],f[r-(1<<k)+1][k]);
    return res;
}

\(O(1)\)实现能查询栈中最小元素

开两个栈,a存原始数据,b存历史上每一个时刻的最小值
举个例子
a:9 2 1 5 3 0 2 <-
b:9 2 1 1 1 0 0 <-
每次插入元素x时,a插入x,b插入min(top(b),x),弹出时一块儿弹,询问时输出top(b)遍历

二分

以前用的二分太傻比了,须要考虑的东西太多(但是我没有脑子),学长就教了一个咕咕咕的二分queue

int l=0,r=1e18;//取个大一点的数
while(l<=r)
{
    int mid=(l+r)>>1;
    if(check(mid)) r=mid-1,ans=mid;
    else l=mid+1;
}
cout<<ans;
double l=0,r=1e18;//取个大一点的数
while(r-l<=eps)
{
    double mid=(l+r)/2;
    if(check(mid)) r=mid,ans=mid;
    else l=mid;
}
cout<<ans;

树和图的深度优先遍历和广度优先遍历

//dfs
void dfs(int x)
{
    visit[x]=1;
    for(int i=head[x];i;i=e[i].Next)
    {
        int to=e[i].v;
        if(visit[to]) continue;
        dfs(to);
    }
}

//bfs
void bfs()
{
    queue<int>q;
    q.push(1);
    d[1]=1;//层数 
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].Next)
        {
            int to=e[i].v;
            if(visit[to]) continue;
            d[to]=d[u]+1;
            q.push(to);
        }
    }
 }

树的dfs序

dfs序的特色:统计

每一个节点x编号在序列中出现两次,并且以这两次出现位置为端点的闭区间就是以x为根的子树的DFS序

void dfs(int x)
{
        a[++len]=x;//记录dfs序
    visit[x]=1;
    for(int i=head[x];i;i=e[i].Next)
    {
        int to=e[i].v;
        if(visit[to]) continue;
        dfs(to);
    }
        a[++len]=x;
}

求树的重心

void dfs(int x)
{
    int max_part=0;//删除掉x后最大子树大小 
    size[x]=1;//子树x的大小 
    visit[x]=1;
    for(int i=head[x];i;i=e[i].Next)
    {
        int to=e[i].v;
        if(visit[to]) continue;
        dfs(to);
        size[x]+=size[y];
        max_part=max(max_part,size[y]);
    }
    max_part=max(max_part,n-size[x]);//n为整颗树的节点数目
    if(max_part<ans)
    {
        ans=max_part;//记录重心对应的max_part值 
        pos=x;//记录重心编号 
     } 
}

图的联通块划分

void dfs(int x)
{
    visit[x]=cnt;
    for(int i=head[x];i;i=e[i].Next)
    {
        int to=e[i].v;
        if(visit[to]) continue;
        dfs(to);
    }
} 
for(int i=1;i<=n;++i)
    if(!visit[i]) cnt++,dfs(i);

拓扑排序

void topsort()
{
    queue<int>q;
    for(int i=1;i<=n;++i) 
        if(du[i]==0) q.push(i);//du在add时记录 
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        a[++len]=u;//记录拓扑序 
        for(int i=head[u];i;i=e[i].Next)
        {
            int to=e[i].v;
            if(--du[to]==0) q.push(to);
        }
    }
 }

使用负数下表

int * z=y+50
z[50]-->y[0]
相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息