奇技淫巧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]
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息