各种模板复习及记忆口诀(持续更新)
模板大复习
本博客适用于复习各种常见模板并且提供记忆方法。
同时本博客也有很多以前的复习或者学习链接,不会或忘记时值得一看。
字符串:
manacher找回文
https://www.luogu.com.cn/problem/P3805
整体翻倍夹#号,R小的为min(R-i,p_2*pos-i),两边拓展不越界,记得更新R上界。
int mana(){
int len=s.size()-1;
for(int i=1;i<=len;i++){
ss[i*2-1]='#';
ss[i*2]=s[i];
}
ss[len*2+1]='#';
int R=0;
int pos=0;
len=2*len+1;
for(int i=1;i<=len;i++){
if(i<R){
p[i]=min(R-i,p[2*pos-i]);
}
else{
p[i]=1;
}
while(i-p[i]>=1&&i+p[i]<=len&&(ss[i-p[i]]==ss[i+p[i]])){
p[i]++;
}
if(i+p[i]>R){
pos=i;
R=i+p[i];
}
}
int ret=0;
for(int i=1;i<=len;i++){
ret=max(ret,p[i]-1);
}
return ret;
}
重点:kmp找broader
https://www.luogu.com.cn/problem/P3375
(从0开始)
初值即为前者值,两端不等j-1前跳,跳到相等值++,记录状态不要忘。
void kmp(){
len=s.size();
int j;
for(int i=1;i<len;i++){
j=p[i-1];
while(s[i]!=s[j]&&j>0){
j=p[j-1];
}
if(s[i]==s[j]){
j++;
}
p[i]=j;
}
}
图论相关:
温馨提示:注意看好边是有向还是无向!
floyd全源最短路
初始化定不能忘,一层k要最外套,里面两层随便跑,用k作为中转点,只要有小就更新。
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
}
djkstra最短路:
https://www.luogu.com.cn/problem/P4779
优先队列来优化,没被访问才进行,访问不会改回0,两个if套一块,外面更新答案,里面添加元素。
稍微注意下重边自环等判断,过了。
struct nod{
int id;
int dis;
bool operator <(const nod &a)const{
return dis>a.dis;
}
};
priority_queue<nod>q;
bool vis[200005];
void djkstra(int ss){
for(int i=1;i<=n;i++){
dis[i]=1e18;
vis[i]=0;
}
dis[ss]=0;
q.push((nod){ss,0});
while(q.size()){
nod tp=q.top();
q.pop();
int x=tp.id;
if(vis[x]){
continue;
}
vis[x]=1;
for(int i=0;i<mp[x].size();i++){
int to=mp[x][i].to;
int val=mp[x][i].val;
if(dis[x]+val<dis[to]){
dis[to]=dis[x]+val;
if(!vis[to]){
q.push((nod){to,dis[to]});
}
}
}
}
}
SPFA最短路
https://www.luogu.com.cn/problem/P3371
入队标记出队消,两层if不能忘,外面更新答案,不在队加元素,超n次有负环。
void spfa(int ss){
for(int i=1;i<=n;i++){
dis[i]=2147483647;
}
dis[ss]=0;
q.push(ss);
vis[ss]=1;
while(q.size()){
int x=q.front();
q.pop();
vis[x]=0;
cnt[x]++;
for(int i=0;i<mp[x].size();i++){
int to=mp[x][i].to;
int val=mp[x][i].val;
if(dis[x]+val<dis[to]){
dis[to]=dis[x]+val;
if(!vis[to]){
vis[to]=1;
q.push(to);
}
}
}
if(cnt[x]>=n){
break;
}
}
}
点双:
https://www.luogu.com.cn/problem/P8435
需要注意每次dfs前的清空,无向边。
三数组三常数,更新未更新点,更新时求答案,外部dfn内部low取小。自身起点无儿子特判有,自身开始1儿子非切点。
void dfs(int x,int fa){
tt++;
dfn[x]=low[x]=tt;
s[++top]=x;
int son=0;
for(int i=0;i<mp[x].size();i++){
int to=mp[x][i];
if(to==fa){
continue;
}
if(!dfn[to]){
son++;
dfs(to,x);
low[x]=min(low[x],low[to]);
if(dfn[x]<=low[to]){
cnt++;
while(s[top+1]!=to){
bcc[cnt].push_back(s[top]);
top--;
}
bcc[cnt].push_back(x);
}
}
low[x]=min(low[x],dfn[to]);
}
if(son==0&&fa==x){
cnt++;
bcc[cnt].push_back(x);
}
}
边双:
https://www.luogu.com.cn/problem/P8436
需要注意重编情况的特判。
(相比点双)
判断拉到最外层,判断条件变相等,特判全部都删除。
void dfs(int x,int fa){
tt++;
dfn[x]=low[x]=tt;
s[++top]=x;
bool f=0;
for(int i=0;i<mp[x].size();i++){
int to=mp[x][i];
if(to==fa&&f==0){
f=1;
continue;
}
if(!dfn[to]){
dfs(to,x);
low[x]=min(low[x],low[to]);
}
low[x]=min(low[x],dfn[to]);
}
if(dfn[x]==low[x]){
cnt++;
while(s[top+1]!=x){
bcc[cnt].push_back(s[top]);
top--;
}
}
}
差分约束:
详情:https://www.cnblogs.com/linghusama/p/17542288.html
为了好记:求最值反着约束,反着连边,反着求路径
例如:求最小,约束>=,连边j,i,找最长路。
二分图最大匹配/最小覆盖。
(当然也可以最大流解决,还是要注意下重边)
https://www.luogu.com.cn/problem/P3386
n次外层不能少,每次清空vis不能忘,遍历全部未访问可接点,rev无值或可更改则更改。
bool match(int x){
for(int i=0;i<mp[x].size();i++){
int to=mp[x][i];
if(vis[to]){
continue;
}
vis[to]=1;
if(!rev[to]||match(rev[to])==1){
rev[to]=x;
return 1;
}
}
return 0;
}
.....
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(match(i)==1){
ans++;
}
}
最大流(dinic)
详情:https://www.cnblogs.com/linghusama/p/17564343.html
说实话,目前就没遇到过这种题,而且这种题限制也多,码量也多。
树型结构:
线段树:
个人觉得...没必要吧
树状数组:
详情:https://www.cnblogs.com/linghusama/p/17455975.html
平衡树(非旋treap)
详情:https://www.cnblogs.com/linghusama/p/17478930.html
笛卡尔树(感觉考的少)
关键是你做题要看出来是这个树。
大不了我线段树nlogn维护,因为他都考你这个树了,我不信他还要O(n)来做
主席树(感觉考的少)
详情:https://www.cnblogs.com/linghusama/p/17697328.html
最小生成树:
krus那个算法就不说了,用并查集排序后乱做
这里主要是用于很多边但点少的prim算法的口诀记忆。
最开始,集合中只有1号节点,然后从1号节点扩展出到所有节点的d值。然后每次将离集合最近的且不在
集合中的点加入集合,让后从这个点往所有点扩展,更新d值,重复以上过程直到所有点都在集合中了。
int prim(){
for(int i=2;i<=n;i++){
dis[i]=0x3f3f3f3f;
}
int ans=0;
int tot=0;
for(int i=0;i<mp[1].size();i++){
int to=mp[1][i].to;
int val=mp[1][i].val;
dis[to]=min(dis[to],val);
}
while(++tot<=n-1){
int mii=0x3f3f3f3f;
vis[now]=1;
for(int i=1;i<=n;i++){
if(!vis[i]&&mii>dis[i]){
mii=dis[i];
now=i;
}
}
ans+=mii;
for(int i=0;i<mp[now].size();i++){
int to=mp[now][i].to;
int val=mp[now][i].val;
dis[to]=min(dis[to],val);
}
}
return ans;
}