单调栈
- 先进后出
- 元素存储有序
- 维护上凸壳
- 例题:P2866
单调队列
-
先进先出
-
元素有单调性
-
deque<int> q; if(q.empty()) { q.push_back(A[i]); } else if(q.back()>A[i]) { while((!q.empty())&&q.back()>A[i]) { q.pop_back(); } q.push_back(A[i]); } else { q.push_back(A[i]); }
-
优化多重背包
- (N)个物品,(M)空间
- 第i个物品只能买(s_i),占(v_i)空间,有(w_i)价值
- 二进制拆分+单调队列
- (f_{i,j}):前(i)种物品耗费(j)空间的最大价值
- (f_{i-1,dots} ightarrow f_{i,dots},iin{x|xin[2,+infty]and xin Z^+})
- 模板题
堆(优先队列)
- 堆排序,堆优化Dijkstra
- 例题:P2857
并查集
-
作用:
- 合并集合
- 查询两个元素是否在同一个集合
-
int find(int x) { if(fa[x]==x) { return x; } return fa[x]=find(fa[x]); } void merge(int x,int y) { xx=find(x),yy=find(y); fa[xx]=yy; }
-
优化:
- 路径压缩
- 按秩合并:小集合连接大集合
树状数组
-
单点修改,区间查询
-
#include<bits/stdc++.h> using namespace std; const int maxn=103,INF=0x7f7f7f7f; struct Node { int val,num; } z[maxn]; int T[maxn]; int n; bool cmp(Node a,Node b) { return a.val==b.val?a.num<b.num:a.val<b.val; } void modify(int x,int y) { //把val[x]替换为val[x]和y中较大的数 for(; x<=n; x+=x&(-x)) T[x]=max(T[x],y); } int query(int x) { //返回val[1]~val[x]中的最大值 int res=-INF; for(; x; x-=x&(-x)) res=max(res,T[x]); return res; } int main() { int ans=0; scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d",&z[i].val); z[i].num=i;//记住val[i]的编号,有点类似于离散化的处理,但没有去重 } sort(z+1,z+n+1,cmp);//以权值为第一关键字从小到大排序 for(int i=1; i<=n; i++) { //按权值从小到大枚举 int maxx=query(z[i].num);//查询编号小于等于num[i]的LIS最大长度 modify(z[i].num,++maxx);//把长度+1,再去更新前面的LIS长度 ans=max(ans,maxx);//更新答案 } printf("%d ",ans); return 0; }
线段树
- 强有力的解题工具
- 支持操作多,满足结合律,常数大
- 建树开4倍空间