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; }
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; }
*最短路能夠試試反着建邊反着跑
拓撲序:入度 出度
歐拉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; }
線段樹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; }
關鍵在於對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; }
字符串:
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; }
差分:
一樣用於優化複雜度
每每是屢次修改單次查詢
開一個差分數組維護影響 //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; }
須要增強的地方:
DP寫很差轉移方程
線段樹不會應用
STL使用不熟練
作題時不能看出要用哪一個算法
代碼能力差