技能樹

 STL:html


 

容器與迭代器的概念
重載運算符

vector:
v.size();
v.push_back();
v[i];

set:
set.insert();
set.erase();
set.begin();
set.end();指到最後一個的後一個
set.count();
set.lower_bound();
set.upper_bound();
set.size();

priority_queue:
Q.push();
Q.pop();
Q.size();
Q.top();
實現普通堆

multiset:
和set相似,刪除的時候特別注意

string:
動態開空間ios

deque:
deq.front();
deq.back();
deq.push_front(x);
deq.pop_front();
deq.push_back(x);
deq.pop_back();

lower_bound();
upper_bound(); 算法

string:
動態開空間

重載運算符:數組

bool operator < (const Vergil &x) const
{
}數據結構

 

 //https://vjudge.net/problem/UVA-10815ide

 

圖與數據結構函數


 

建圖 :鄰接矩陣  鄰接表優化

圖的dfs和bfs :    //魔板ui

二分圖染色: //封鎖陽光大學spa

最短路: SPFA&&dij

// 差分約束系統

dij模板:

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define maxn 500005
struct Vergil
{
    int id,d;
    bool operator < (const Vergil &a) const
    {
        return d>a.d;
    }
};
int n,m,l,s,dis[maxn];
int pre[maxn],last[maxn],other[maxn],len[maxn];
bool vis[maxn];
priority_queue<Vergil> q;

inline int read(void)
{
    int x=0;
    char ch=getchar();
    while (ch>'9'||ch<'0') ch=getchar();
    while (ch>='0'&&ch<='9') 
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}

void connect(int x,int y,int z)
{
    l++;
    pre[l]=last[x];
    last[x]=l;
    other[l]=y;
    len[l]=z;
}

void update(int u,int d)
{
    Vergil tmp;
    tmp.id=u;
    tmp.d=d;
    q.push(tmp);
}

void dijkstra(int s)
{
    dis[s]=0;
    update(s,0);
    while (!q.empty())
    {
        Vergil tmp=q.top();q.pop();
        int u=tmp.id;
        if (vis[u]) continue;
        vis[u]=1;
        for (int p=last[u];p;p=pre[p]) 
        {
            int v=other[p];
            if (dis[v]>dis[u]+len[p]) 
            {
                dis[v]=dis[u]+len[p];
                update(v,dis[v]);
            }
        }
    }
}

int main()
{
    n=read();m=read();s=read();
    for (int i=1;i<=m;i++) 
    {
        int x=read(),y=read(),z=read();
        connect(x,y,z);
    }
    for (int i=1;i<=n;i++) dis[i]=2147483647;
    dijkstra(s);
    for (int i=1;i<=n;i++) printf("%d ",dis[i]);
    return 0;
}
View Code

 

spfa模板(容易被卡):

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define mo 10000
#define maxn 10010
#define maxm 500010
int pre[maxm],last[maxn],other[maxm],len[maxm];
int dis[maxn],vis[maxn],que[maxn];
int l,x,y,z,m,n,s,h,t;
using namespace std;
void con(int x,int y,int z)
{
    l++;
    pre[l]=last[x];
    last[x]=l;
    other[l]=y;
    len[l]=z;
}
void spfa(int s)
{
    memset(dis,0x3f,sizeof(dis));
    int h=0,t=1;
    dis[s]=0;
    que[1]=s;
    while(h!=t)
    {
        h=h%mo+1;
        int u=que[h];
        vis[u]=0;
        for(int p=last[u];p;p=pre[p])
        {
            int v=other[p];
            if(dis[v]>dis[u]+len[p])
        {
            dis[v]=dis[u]+len[p];
            if(!vis[v])
            {
                t=t%mo+1;
                que[t]=v;
                vis[v]=1;
            }
        }
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;i++)
    {
    int x,y,z;
    scanf("%d%d%d",&x,&y,&z);
    con(x,y,z);
    }
    spfa(s);
    for(int i=1;i<=n;i++)
    {
        if(dis[i]!=dis[0])
        printf("%d ",dis[i]);
        else printf("%d ",2147483647);
    }
    return 0;
}
View Code

*最短路能夠試試反着建邊反着跑 

 

拓撲序入度 出度 

歐拉XX:

 無向圖:

歐拉道路: 只有兩個奇度點                                         歐拉回路: 每一個點都是偶度

有向圖:

歐拉道路: 一個點入度=出度+1 一個點出度=入度+1    歐拉回路:入度=出度       //無序字母對  騎馬修柵欄

迴路屬於道路

樹:

DFS序
重心:刪除這個點後樹的最大兒子最小   採用一遍dfs,計算每一個點的相連的最大的連通塊規模,求取最大值;再在全部最大值中找出最小的,這個點就是重心。
直徑:樹的兩個距離最長的點

一個點的最遠路 必是直徑的一點

字典樹

最小生成樹 

樹狀數組

 

並查集        //銀河英雄傳說

*種類並查集

*加權並查集%

分塊

最近公共祖先

 

線段樹:

基於二分的二叉樹結構  用於區間統計   優化複雜度

對於區間的修改  //借教室

關於DP的優化    //LIS

 線段樹1模板:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100005
typedef long long LL;
struct tree
{
    int l,r;
    LL sum,lazy;
}t[maxn*4];
int a[maxn],n,m;

void build(int x,int l,int r) 
{
    t[x].l=l;t[x].r=r;
    if (l==r) 
    {
        t[x].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(2*x,l,mid);
    build(2*x+1,mid+1,r);
    t[x].sum=t[2*x].sum+t[2*x+1].sum;
}

void update(int x) 
{
    t[2*x].sum+=(t[2*x].r-t[2*x].l+1)*t[x].lazy;
    t[2*x+1].sum+=(t[2*x+1].r-t[2*x+1].l+1)*t[x].lazy;
    t[2*x].lazy+=t[x].lazy;
    t[2*x+1].lazy+=t[x].lazy;
    t[x].lazy=0;
}

void change(int x,int l,int r,int z) 
{
    if (t[x].l==l&&t[x].r==r) 
    {
        t[x].sum+=(LL)(r-l+1)*z;
        t[x].lazy+=z;
        return;
    }
    if (t[x].lazy) update(x);
    int mid=(t[x].l+t[x].r)>>1;
    if (r<=mid) change(2*x,l,r,z);
    else if (l>mid) change(2*x+1,l,r,z);
    else 
    {
        change(2*x,l,mid,z);
        change(2*x+1,mid+1,r,z);
    }
    t[x].sum=t[2*x].sum+t[2*x+1].sum;
}

LL query(int x,int l,int r) 
{
    if (t[x].l==l&&t[x].r==r) return t[x].sum;
    if (t[x].lazy) update(x);
    int mid=(t[x].l+t[x].r)>>1;
    if (r<=mid) return query(2*x,l,r);
    else if (l>mid) return query(2*x+1,l,r);
    else return query(2*x,l,mid)+query(2*x+1,mid+1,r);    
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,1,n);
    for (int i=1;i<=m;i++) 
    {
        int opt,x,y,z;
        scanf("%d%d%d",&opt,&x,&y);
        if (opt==1) 
        {
            scanf("%d",&z);
            change(1,x,y,z);
        }
        else printf("%lld\n",query(1,x,y));
    }
    return 0;
}
View Code

線段樹2模板  (乘法)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100005
typedef long long LL;
struct tree
{
    int l,r;
    LL sum,lazy1,lazy2;
}t[maxn*4];
int n,m,a[maxn],mo;

void build(int x,int l,int r)
{
    t[x].l=l;t[x].r=r;t[x].lazy1=1;
    if (l==r) 
    {
        t[x].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(2*x,l,mid);
    build(2*x+1,mid+1,r);
    t[x].sum=(t[2*x].sum+t[2*x+1].sum)%mo;
}

void update(int x) 
{
    LL mul=t[x].lazy1;
    LL add=t[x].lazy2;
    t[2*x].sum=(mul*t[2*x].sum%mo+add*(t[2*x].r-t[2*x].l+1)%mo)%mo;
    t[2*x+1].sum=(mul*t[2*x+1].sum%mo+add*(t[2*x+1].r-t[2*x+1].l+1)%mo)%mo;
    (t[2*x].lazy1*=mul)%=mo;
    (t[2*x+1].lazy1*=mul)%=mo;
    (t[2*x].lazy2*=mul)%=mo;
    (t[2*x+1].lazy2*=mul)%=mo;
    (t[2*x].lazy2+=add)%=mo;
    (t[2*x+1].lazy2+=add)%=mo;
    t[x].lazy1=1;
    t[x].lazy2=0;
}

void change(int x,int l,int r,int z,int o) 
{
    if (t[x].l==l&&t[x].r==r) 
    {
        if (o==2) (t[x].sum+=(LL)z*(r-l+1))%=mo,(t[x].lazy2+=z)%=mo;
        else t[x].sum=((LL)z*t[x].sum)%mo,(t[x].lazy1*=(LL)z)%=mo,(t[x].lazy2*=(LL)z)%=mo;
        return;
    }
    if (t[x].lazy1!=1||t[x].lazy2) update(x);
    int mid=(t[x].l+t[x].r)>>1;
    if (l>mid) change(2*x+1,l,r,z,o);
    else if (r<=mid) change(2*x,l,r,z,o);
    else 
    {
        change(2*x,l,mid,z,o);
        change(2*x+1,mid+1,r,z,o);
    }
    t[x].sum=(t[2*x].sum+t[2*x+1].sum)%mo;
}

int query(int x,int l,int r) 
{
    if (t[x].l==l&&t[x].r==r) return t[x].sum;
    if (t[x].lazy1!=1||t[x].lazy2) update(x);
    int mid=(t[x].l+t[x].r)>>1;
    if (l>mid) return query(2*x+1,l,r);
    else if (r<=mid) return query(2*x,l,r);
    else return (query(2*x,l,mid)+query(2*x+1,mid+1,r))%mo;
}

int main()
{
    scanf("%d%d%d",&n,&m,&mo);
    for (int i=1;i<=n;i++) scanf("%d",a+i);
    build(1,1,n);
    for (int i=1;i<=m;i++) 
    {
        int opt,x,y,z;
        scanf("%d%d%d",&opt,&x,&y);
        if (opt!=3) scanf("%d",&z),change(1,x,y,z,opt);
        else printf("%d\n",query(1,x,y));
    }
    return 0;
}
View Code

關鍵在於對lazy標記的理解

 

 ST表模板(倍增)

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int n,m,mx[1000010][17],l,r;
inline int st(int l,int r)
{
    int k=log(r-l+1)/log(2);
    return max(mx[l][k],mx[r-(1<<k)+1][k]);
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    cin>>mx[i][0];
    for(int j=1;j<17;j++)
    for(int i=1;i<=n;i++)
    {
    if(i+(1<<j)-1>n)continue;
    mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
    }
    for(int i=1;i<=m;i++)
    {
    cin>>l>>r;
    cout<<st(l,r)<<endl;
    }
    return 0;
    
}
View Code

 字符串:

KMP

 

 哈希表

存儲數據  // a-b   

桶的優化

 

算法


 

DP:

Vergil:

首先是設計狀態,咱們確定是要有一個一維或多維的狀態的,那麼如何設計它們的意義呢,首先咱們能夠分析出題目中的一些重要的量,好比當前時間,選了幾個,考慮到了哪裏,對於這些狀態咱們是要以一個值來表示這些狀態的最優狀況,好比f[i][j][k]..=P,i,j,k表示狀態,P表示那個值,咱們i,j,k,P都是這些重要的量,咱們應該先把這些重要的量列出,而後感受一下如何設計狀態容易轉移,通常來講設計了一個好的狀態剩下的事情都比較好辦。

若是這個狀態不是太好,咱們能夠考慮優化轉移,咱們能夠再開一個別的數組維護咱們轉移的信息,好比說維護最小值,或者用高級數據結構維護,或者發現狀態的一些性質(單調性),這樣就能更快的轉移。

其實動態規劃也是考慮了全部的狀態,若是說你設計的DP沒有將全部的狀態考慮到,那麼必定是錯誤的,動態規劃的實質就是枚舉了全部的狀態,而後保留最大值。

我的認爲動態規劃就是一個分類,動態規劃的狀態就是分類的標準,動態規劃在每一中類別中都取得最優解,另外對於每一個基本元素來講,通常都有幾個狀態,好比說揹包問題中每一個物品的選與不選,或者是這個元素放在哪一個位置等等等等,考慮到每一個元素的狀態也有助於咱們設計總體的狀態。

區間DP:

由小到大         //合併石子

揹包DP:

揹包九講

https://www.cnblogs.com/jbelial/articles/2116074.html

選與不選         //津津的儲蓄計劃

樹形DP:

樹形揹包      //選課

選擇結點      //沒有上司的舞會

狀壓DP:

用二進制串進行選與不選    //炮兵陣地   互不侵犯king

貪心(玄學)

1.數學式子推出結論

2.考慮臨界   感覺貪心策略可不可行(用心去感覺~)

二分:

*最大的最小值

二分需具備單調性

若是是單峯函數 則需三分 //借教室  期末考試 通向奧格瑞瑪的道路

三分:期末考試代碼

 

 
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100005
typedef long long LL;
LL A,B,C,ans;
int t[maxn],b[maxn],n,m,L,R;
 
LL f(int x)
{
    LL res1=0;
    LL res2=0;
    LL ff=0;
    for (int i=1;i<=m;i++) 
        if (b[i]<x) res1+=(x-b[i]);
    for (int i=1;i<=m;i++)
        if (b[i]>x) res2+=(b[i]-x);
    if (A>=B) ff=res2*B;
    else
    {
        if (res1>=res2) ff=res2*A;
        else
        {
            ff=res1*A;
            res2-=res1;
            ff+=res2*B;
        }
    }
    for (int i=1;i<=n;i++) 
        if (t[i]<x) ff+=C*(x-t[i]);
    return ff;
}
 
int main()
{
    scanf("%lld%lld%lld",&A,&B,&C);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&t[i]);
    for (int i=1;i<=m;i++) scanf("%d",&b[i]),R=max(R,b[i]);
    if (C>1e6+1) 
    {
        int x=1e5+1;
        for (int i=1;i<=n;i++) x=min(x,t[i]);
        printf("%lld\n",f(x));
        return 0;
    }
    L=1;ans=1e18;
    while (R-L>=5) 
    {
        int mid1=(L+R)>>1;
        int mid2=(mid1+R)>>1;
        LL ans1=f(mid1);
        LL ans2=f(mid2);
        if (ans1<ans2) 
        {
            ans=min(ans,ans1);
            R=mid2;
        }
        else
        {
            ans=min(ans,ans2);
            L=mid1;
        }
    }
    for (int i=L;i<=R;i++) 
        ans=min(ans,f(i));
    printf("%lld\n",ans);
    return 0;
}
View Code

 

差分:

一樣用於優化複雜度

每每是屢次修改單次查詢

開一個差分數組維護影響     //luogu3397 地毯

 數學:

 


 

矩陣快速冪:   //斐波那契數列

歐拉篩素數

#include<cstdio>
#include<iostream>
using namespace std;
int n,m;
int i,j;
bool flag[10000010];
int p[1000010];
int tot,x;
int main()
{
    cin>>n>>m;
    flag[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(flag[i]==0)
        {
        tot++;
        p[tot]=i;
         }
    for(int j=1;j<=tot;j++)
    {
        if(p[j]*i>n) break;
        flag[p[j]*i]=1;
        if(i%p[j]==0) break;
    }
   }
   for(int i=1;i<=m;i++)
   {
       cin>>x;
       if(flag[x]==0) cout<<"Yes"<<endl;
       else cout<<"No"<<endl; 
   }
   return 0;
   
}
View Code

 

 

須要增強的地方:

DP寫很差轉移方程

線段樹不會應用

STL使用不熟練

作題時不能看出要用哪一個算法

代碼能力差

相關文章
相關標籤/搜索