基础算法大全(更新ing
1 前缀和 /// 给定一组数,求任意区间的总和 #include<bits/stdc++.h> using namespace std; const int N=100010; int n,a[N],s[N],m; int main() { cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i]; s[i]=s[i-1]+a[i]; } while(m--) { int l,r; cin>>l>>r; cout<<s[r]-s[l-1]<<endl; } return 0; } 1-2 矩阵的前缀和 思路://https://blog.csdn.net/m0_62881629/article/details/124762394?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168250250916800227440048%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=168250250916800227440048&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-5-124762394-null-null.142^v86^control,239^v2^insert_chatgpt&utm_term=P1387%20%E6%9C%80%E5%A4%A7%E6%AD%A3%E6%96%B9%E5%BD%A2&spm=1018.2226.3001.4187 题目链接://https://www.luogu.com.cn/problem/P1387 ///s[i] [j] = s[i-1][j] + s[i][j-1 ] + a[i] [j] - s[i-1][ j-1] #include<iostream> #include<cstdio> using namespace std; const int N=1010; int a[N][N],s[N][N]; int main() { int n,m,q; scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1]; while(q--) { int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); printf("%d\n",s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]); } return 0; } 洛谷:P1387 #include <bits/stdc++.h> using namespace std; int n,m,ans,tot,cnt; int s[101][101],ma[101][101],sum[101][101]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>ma[i][j]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) sum[i][j]=ma[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];//前缀和 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int p=i,q=j,tmp=1;//(p,q)为起点 逐步扩展,tmp相当于长度范围. if(ma[p][q]==1 && sum[p][q]-sum[i-1][q]-sum[p][j-1]+sum[i-1][j-1]==tmp*tmp && p<=n&&q<=m) { while(ma[p][q]==1&&sum[p][q]-sum[i-1][q]-sum[p][j-1]+sum[i-1][j-1]==tmp*tmp && p<=n&&q<=m) p++,q++,tmp++; ans=max(ans,tmp-1); } } printf("%d\n",ans); } 2-1 一维差分 ///在差分中,b数组是a[i]=b[1]+b[2]+...+b[i];这样的形式叫做差分数组 ///也就是a数组是b数组的前缀和; 给出一组数组,要求你在某个区间里加上一个数c,数据有多组 例如:1 2 3 4 在 1-2 区间+1,在2-3区间+2,在1-4区间+1; 最终结果是 3 6 6 5 代码实现: ///由于前缀和的存在,如果给b[l]+c,那么a数组从l到n都加上了c,那么如果给b[r+1]-c,这就实现了从l到r的加c形式; #include<bits/stdc++.h> using namespace std; const int N=100010; int a[N],b[N]; int n,m; void Insert(int l,int r,int c) { b[l]+=c; b[r+1]-=c; } int main() { cin>>n>>m;//n为数组的长度,m为加的次数 for(int i=1;i<=n;i++) { cin>>a[i]; Insert(i,i,a[i]);///从区间到区间末,加上c,这一步是创建差分数组b } while(m--) { int l,r,c; cin>>l>>r>>c; Insert(l,r,c);///进行操作; } for(int i=1;i<=n;i++) { b[i]+=b[i-1];///更新数组; cout<<b[i]<<" "; } return 0; } 2-2 差分矩阵(二维差分) 与一维差分差不多,和前缀和一样,只是多一个公式 #include<bits/stdc++.h> using namespace std; const int N=1010; int a[N][N],b[N][N]; int n,m,q;//nxm的矩阵,q次访问; void Insert(int x1,int y1,int x2,int y2,int c) { b[x1][y1]+=c; b[x2+1][y1]-=c; b[x1][y2+1]-=c; b[x2+1][y2+1]+=c; } int main() { cin>>n>>m>>q; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>a[i][j]; Insert(i,j,i,j,a[i][j]); } while(q--) { int x1,y1,x2,y2,c; cin>>x1>>y1>>x2>>y2>>c; Insert(x1,y1,x2,y2,c); } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1]; cout<<b[i][j]<<" "; } cout<<endl; } return 0; } 3-1 双指针 求最长不重复序列 #include<bits/stdc++.h> using namespace std; const int N=100010; int n,res=0; int a[N],s[N];///s用来储存a[i]中的数字出现的次数 int main() { cin>>n; for(int i=0;i<n;i++ cin>>a[i]; for(int i=0;i<n;i++) { s[a[i]]++; while(s[a[i]]>1)///循环,直到j与i的区间内没有重复元素; { s[a[j]]--; j++; } res=max(res,i-j+1); } cout<<res; return 0; } 4-1 离散化 #include<bits/stdc++.h> using namespace std; const int N=300010; typedef pair<int,int>PII; int n,m; int a[N],s[N]; vector<int> alls; vector<PII>add,query; int find(int x) { int l=0,r=alls.size()-1; while(l<r) { int mid=l+r>>1; if(alls[mid]>x) r=mid-1; else l=mid+1; } return l; } int main() { cin>>n>>m; for(int i=0;i<n;i++) { int x,c; cin>>x>>c; add.push_back({x,c}); alls.push_back(x); } for(int i=0;i<m;i++) { int l,r; cin>>l>>r; query.push_back({l,r}); alls.push_back(l); alls.push_back(r); } sort(alls.begin(),alls.end()); alls.erase(unique(alls.begin(),alls.end()),alls.end()); for(auto i:add) { int x=find(i.first); a[x]+=i.second; } for(int i=1;i<=alls.size();i++) s[i]=s[i-1]+a[i]; for(auto i:query) { int l=find(i .first),r=find(i.second); cout<<s[r]-s[l-1]<<endl; } return 0; } 5-1 Trie树,快速存储字符串和询问字符串 #include<bits/stdc++.h> using namespace std; const int N=100010; int son[N][26],cnt[N],idx; void Insert(char str[])///插入操作 { int p=0; for(int i=0;str[i];i++) { int u=str[i]-'a'; if(!son[p][u]) son[p][u]=++idx;///如果没有子节点,要自己创建子节点 p=son[p][u]; } cnt[p]++; } int query(char str[])///询问操作 { int p=0; for(int i=0;str[i];i++) { int u=str[i]-'a'; if(!son[p][u]) return 0;///没有子节点,说明不是这个字符串,返回0; p=son[p][u]; } return cnt[p]; } int main() { int n; cin>>n; while(n--) { char x; cin>>x; char y[N]; cin>>y; if(x=='I') Insert(y); else { int res=0; res=query(y); cout<<res<<endl; } } } 6-1 并查集 ///find函数可能有点难理解,自己尝试画下图随便理解好吧 ///M是合并,Q是询问是否在一个树中 #include<bits/stdc++.h> using namespace std; const int N=10010; int n,m; int q[N]; int find(int x) { if(q[x]!=x) q[x]=find(q[x]));///如果x不是树的头结点,向上循环查找到头结点为止. ///可以自己画图理解一下; return q[x]; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) q[i]=i; while(m--) { char op[2]; int a,b; scanf("%s%d%d",&op,&a,&b); if(op[0]=='M') q[find(a)]=find(b); else { if(find(a)==find(b)) cout<<"YES"<<endl; else cout<<"NO"<<endl; } } return 0; } 6-2 查并集,但是可能输出长度 #include<bits/stdc++.h> using namespace std; const int N=100010; int n,m; int p[N],size[N]; int find(int x) { if(p[x]!=x) p[x]=find(p[x]); return p[x]; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) { p[i]=i; size[i]=1; } while(m--) { ///C为合并,Q1为 检查是否在同一区间,Q2检查长度; char op[2]; scanf("%s",&op); int a,b; if(op[0]=='C') { cin>>a>>b; if(find(a)==find(b)) continue;///特判 size[find(b)]+=size[find(a)]; p[find(a)]=find(b); } else if(op[1]=='1') { cin>>a>>b; if(find(a)==find(b)) cout<<"YES"<<endl; else cout<<"No"<<endl; } else if(op[1]=='2') { cin>>a; cout<<size[find(a)]<<endl; } } } 6-3 食物链 https://www.luogu.com.cn/problem/P2024 ///这题是真难,看视频加理解一共花了俩小时 #include<bits/stdc++.h> using namespace std; const int N=100010; int n,m,res=0; int p[N],d[N]; int find(int x) { if(p[x]!=x)///与以往不同,这里的d数组刚开始的作用是,x节点与父节点的距离,经过find函数递归之后 ///d数组变成了,x节点到头节点的距离,这样就可以来判断是不是同一类和接下来做题了 { int t=find(p[x]); d[x]+=d[p[x]];///因为要用到p[x],所以先储存; p[x]=t; } return p[x]; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) p[i]=i; while(m--) { int a,b,c; cin>>c>>a>>b; if(a>n||b>n) res++; else { if(c==1) { int pa=find (a),pb=find(b); if(pa==pb&&(d[a]-d[b])%3) res++;///3个一循环;如果A和B是同类,而且他俩已经在合并过了,那么两者的距离相减,如果余三不得0那么就是错的; else { p[pa]=pb; d[pa]=d[b]-d[a]; } } else { int pa=find(a),pb=find(b); if(pa==pb&&(d[a]-d[b]-1)%3) res++; else if(pa!=pb) { p[pa]=pb; d[pa]=d[b]+1-d[a]; } } } } cout<<res; return 0; } 6-4 自动程序检测装置 https://www.luogu.com.cn/problem/P1955 ///这个题是我得知有查并集这个算法的起初 ///查并集+离散化,题目i和j都开到10的九次方了,不用离散化等着爆吧 ///本题思路 #include<bits/stdc++.h> using namespace std; const int N=400010; int t,n; int a[2*N],p[N],d[2*N],b[N],c[N]; int find(int x)///典 { if(p[x]!=x) p[x]=find(p[x]); return p[x]; } int main() { cin>>t; while(t--) { cin>>n; for(int i=1;i<=n;i++) { cin>>a[2*i-1]>>a[2*i]>>c[i]; d[2*i-1]=a[2*i-1],d[2*i]=a[2*i]; } sort(d+1,d+2*n+1); int h=0; b[0]=-1; for(int i=1;i<=2*n;i++) if(b[h]!=d[i]) b[++h]=d[i];///离散化完成,用了两次这个离散化模板了,感觉yxc老师的那个离散化模板用不了一点 for(int i=1;i<=h;i++) p[i]=i;///更新爹节点 for(int i=1;i<=n;i++) { if(c[i]==0) continue; int x=lower_bound(b+1,b+h+1,a[2*i-1])-b; int y=lower_bound(b+1,b+h+1,a[2*i])-b; if(find(x)==find(y)) continue; else p[find(x)]=find(y);///将所有相等的元素,放进树里面;接下来的就是狠狠的查找有没有内鬼 } bool f=false; for(int i=1;i<=n;i++) { if(c[i]==1) continue; int x=lower_bound(b+1,b+h+1,a[2*i-1])-b; int y=lower_bound(b+1,b+h+1,a[2*i])-b; if(find(x)==find(y))///查找内鬼,如果有人在相等的树里面,就是内鬼! { cout<<"NO"<<endl; f=true; break; } } if(!f) cout<<"YES"<<endl; } return 0; } 7-0 利用动态二维数组创建无权邻接表 #include<bits/stdc++.h> using namespace std; const int N=100010; vector<int>g[N]; int n,m; int main() { cin>>n>>m; for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; g[x].push_back(y); g[y],push_back(x); } for(int i=1;i<=n;i++) { cout<<i<<":"<<" "<<endl; for(auto v:g[i]) cout<<v<<" "; cout<<endl; } } 7-1 创立有权邻接表 #include<bits/stdc++.h> using namespace std; const int N=100010; int n,m; struct node { int to; int val; }; vector<node>g[N]; int main() { cin>>n>>m; for(int i=1;i<=m;i++) { int a,b,c; node tmp; cin>>a>>b>>c; tmp.to=b; tmp.val=c; g[a].push_back(tmp); } for(int i=1;i<=n;i++) { cout<<i<<":"<<endl; for(auto v:g[i]) cout<<v.to<<" "<<v.val; cout<<endl; } return 0; }