洛谷模板:P1439 【模板】最长公共子序列
O(n^2)解法
//最长上升子序列的O(n的平方)解法 #include<iostream> #include<cstdio> #include<queue> #include<algorithm> #include<vector> using namespace std; int a[100005],b[100005],c[100005],f[100005]; //f[i]表示以第i个元素结尾的最长上升子序列的长度 int main() { int n=0,ans=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); c[a[i]]=i;//将a[i]映射为i } for(int i=1;i<=n;i++) scanf("%d",&b[i]); for(int i=1;i<=n;i++) { f[i]=1;//初始化f[i]为1 for(int j=1;j<i;j++) if(c[b[j]]<c[b[i]]) f[i]=max(f[i],f[j]+1); //如果可以延续由前面的元素结尾的最长上升子序列并且延续后的长度大于目前长度,就更新 ans=max(ans,f[i]);//维护最大值 } printf("%d",ans);//输出答案 return 0; }
O(nlogn)解法
//最长上升子序列的O(nlogn)解法 #include<iostream> #include<cstdio> #include<queue> #include<algorithm> #include<vector> using namespace std; int a[100005],b[100005],c[100005],f[100005]; //f[i]长度为i的上升子序列末尾的最小值 int find(int l,int r,int x)//创立二分查找函数,作用:在f数组的l~r的范围内找一个最小的比x大的数,返回其下标 { while(l<r)//如果l、r相邻,就表示找到了 { int mid=(l+r)/2;//求中点 if(f[mid]>x) r=mid;//如果当前的数比x大就继续往左找 else l=mid+1;//否则就继续往右找 } return r;//返回下标 } int main() { int n=0,len=0; scanf("%d",&n);//读入序列长度 for(int i=1;i<=n;i++) { scanf("%d",&a[i]);//读入第一个序列 c[a[i]]=i;//将a[i]映射为i } for(int i=1;i<=n;i++) scanf("%d",&b[i]);//读入第二个序列 for(int i=1;i<=n;i++) if(c[b[i]]>f[len]) f[++len]=c[b[i]];//如果当前元素大于栈顶元素,就直接入栈 else f[find(1,len,c[b[i]])]=c[b[i]];//否则就在f数组内找一个最小的比它大的数替换 // else f[lower_bound(f+1,f+len+1,c[b[i]])-f]=c[b[i]]; //用stl的二分 printf("%d",len);//输出答案,即长度 return 0;//结束 }
洛谷模板:P3372 【模板】线段树 1
//L3372 -【模板】线段树1 #include<iostream> #include<cstdio> using namespace std; //book数组为懒标记,即先存下每个结点还未完成的操作,等需要用到时再更新,大大优化时间复杂度 long long a[100005],tree[450000],book[450000]; void make_tree(int p,int l,int r)//建树,表示此时的结点是p,所代表的区间为[l,r]时的情况 { if(l==r)//如果只剩一个数 { tree[p]=a[l];///直接赋值 return;//结束 } int mid=(l+r)/2; make_tree(p*2,l,mid);//考虑左儿子 make_tree(p*2+1,mid+1,r);//考虑右儿子 tree[p]=tree[p*2]+tree[p*2+1];//当前结点的值等于左右儿子的值之和 } void plus_node(int p,int l,int r,long long k)//将结点p所表示的区间中的元素都加上k { tree[p]+=k*(r-l+1);//所表示的区间每个元素都要加上k,所以总共是加上(r-l+1)个k book[p]+=k;//懒标记 } void clean_l(int p,int l,int r)//清除当前节点p的懒标记,将懒标记传递给左右儿子用来更新结点的值 { int mid=(l+r)/2; plus_node(p*2,l,mid,book[p]);//传给左儿子 plus_node(p*2+1,mid+1,r,book[p]);//传给右儿子 book[p]=0;//清除懒标记 } void plus_xyk(int p,int l,int r,int x,int y,long long k)//将区间[x,y]都加上k { if(l==x&&r==y)//如果当前结点所表示的区间正好与需要操作的区间相等 { plus_node(p,l,r,k);//将当前节点所表示的区间中的元素都加上k return;//结束 } clean_l(p,l,r);//清除结点p的懒标记,更新左右儿子的值 int mid=(l+r)/2; if(y<=mid) plus_xyk(p*2,l,mid,x,y,k);//如果需要操作的区间在左儿子所代表的区间中,就处理左儿子所代表的区间 else if(x>mid) plus_xyk(p*2+1,mid+1,r,x,y,k);//如果需要操作的区间在右儿子所代表的区间中,就处理右儿子所代表的区间 else//否则就说明当前结点所代表的区间包含了需要操作的区间 ,然后将需要操作的区间一分为二,并分别处理左右儿子所代表的区间 { plus_xyk(p*2,l,mid,x,mid,k); plus_xyk(p*2+1,mid+1,r,mid+1,y,k); } tree[p]=tree[p*2]+tree[p*2+1];//当前结点的值等于其左右儿子的值之和 } long long find_xy(int p,int l,int r,int x,int y)//计算区间[x,y]中所有元素的和 { if(l==x&&r==y) return tree[p];//如果当前结点所代表的区间等于目标区间,直接返回结点的值 clean_l(p,l,r);//清除结点p的懒标记,更新左右儿子的值 int mid=(l+r)/2; if(y<=mid) return find_xy(p*2,l,mid,x,y);//如果目标区间在左儿子所代表的区间中,就处理左儿子所代表的区间 if(x>mid) return find_xy(p*2+1,mid+1,r,x,y);//如果目标区间在右儿子所代表的区间中,就处理右儿子所代表的区间 return find_xy(p*2,l,mid,x,mid)+find_xy(p*2+1,mid+1,r,mid+1,y);//否则就说明当前结点所代表的区间包含了目标区间 ,然后将目标区间一分为二,并分别处理左右儿子所代表的区间 } int main() { int n=0,m=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); make_tree(1,1,n);//建树 for(int i=1;i<=m;i++) { int t=0,x=0,y=0; long long k=0; scanf("%d",&t); if(t==1) { scanf("%d%d%lld",&x,&y,&k); plus_xyk(1,1,n,x,y,k);//操作一段区间 } else { scanf("%d%d",&x,&y); printf("%lld ",find_xy(1,1,n,x,y));//返回一段区间的和 } } return 0; }
洛谷模板:P3375 【模板】KMP字符串匹配
//KMP【模板】 #include<iostream> #include<cstdio> #include<cstring> using namespace std; //next[i]表示一个字符串从下标0到下标i的最长相等前后缀中前缀最后一位的下标 int next[1000005]; char s1[1000005],s2[1000000]; void getNext(char s[])//求next数组 { next[0]=-1; int j=-1,len=strlen(s); for(int i=1;i<len;i++) { while(j!=-1&&s[i]!=s[j+1]) j=next[j]; if(s[i]==s[j+1]) j++; next[i]=j; } return; } void KMP(char text[],char pattern[])//KMP主体 { int n=strlen(text),m=strlen(pattern),j=-1; getNext(pattern);//求模式串的next数组 for(int i=0;i<n;i++) { while(j!=-1&&text[i]!=pattern[j+1]) j=next[j]; if(text[i]==pattern[j+1]) j++; if(j==m-1)//如果匹配成功 { printf("%d ",i-m+1+1);//输出坐标 j=next[j]; } } return; } int main() { scanf("%s%s",s1,s2); KMP(s1,s2); int len=strlen(s2); for(int i=0;i<len;i++) printf("%d ",next[i]+1); return 0; }
洛谷模板: P3367 【模板】并查集
/*并查集模板 */ #include<iostream> #include<cstdio> #include<fstream> #include<algorithm> #include<string> #include<sstream> #include<cstring> using namespace std; int N=0,M=0,F[10005]; void csh()//初始化 { for(int i=1;i<=N;i++) F[i]=i; return; } int find(int x)//找祖先 { if(F[x]==x) return x;//如果这个人是自己是自己的祖先,就返回 return F[x]=find(F[x]);//不然的话就继续找 } void Merge(int x,int y)//合并 { int a=find(x),b=find(y);//找x和y的祖先 if(a!=b) F[b]=a;//如果不同就合并 } int main() { scanf("%d%d",&N,&M); csh(); for(int i=1;i<=M;i++) { int x=0,y=0,z=0; scanf("%d%d%d",&z,&x,&y); if(z==1) Merge(x,y);//合并操作 else if(find(x)==find(y)) printf("Y ");//查询操作 else printf("N "); } return 0; }
洛谷模板:P3366 【模板】最小生成树
克鲁斯卡尔算法
//最小生成树模板,克鲁斯卡尔算法,思路如下: //首先按照边的权值进行从小到大排序,每次从剩余的边中选择权值较小且 //边的两个顶点不在同一个集合内的边(就是不会产生回路的边), //加入到生成树中,直到加入了n-1条边为止。 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m; int f[50001],sum,ans;//f数组根据实际大小来设置,要比n最大值大1 struct node//第一次用结构体,好兴奋啊,好高大上啊!2333 { int x_start,y_end,z_bian;//结构体保存起点x_start,终点y_end,以及边z_bian } e[200001];//储存边 int cmp(node a,node b) //node是自定义的结构体类型 { return a.z_bian<b.z_bian;//边从小到大快排的规则 } void init()//初始化图的各个点,每个点都是独立的一个集合 { int i; for(i=1;i<=n;i++) f[i]=i; } int find(int x)//查找x的上级并路径压缩 { if(f[x]==x) return x; return f[x]=find(f[x]); } void HB(int x,int y)//合并集合 { int t1=find(x); int t2=find(y); if(t1!=t2) f[t2]=t1; } int main() { int i; cin>>n>>m; init();//初始化 for(i=1;i<=m;i++) cin>>e[i].x_start>>e[i].y_end>>e[i].z_bian;//输入边 并用数据储存起来 //这里不能用边输入边判断了。 sort(e+1,e+m+1,cmp);//把边从小到大排序 for(i=1;i<=m;i++) { if(find(e[i].x_start)!=find(e[i].y_end))//如果这条边的两端顶点不在同一个集合 ,就合并在一个集合里 //那如果两个点在同一个集合就跳过,也说是不选取这条边, //因为会产生回路或者。。。。。。 { HB(e[i].x_start,e[i].y_end); //把这条边的两个端点合并在一个集合 ans=ans+e[i].z_bian; //把这条边加上去,计算边的权值和 sum++;//用来统计已用了多少条边, } if(sum==n-1) break;//如果已有n-1条边,说明图已连通,不用再找下去了。 } if(sum<n-1) cout<<"orz";//判断图是否连通 else cout<<ans; //for(i=1;i<=m;i++) //测试排序用 //printf("%d %d %d ",e[i].x_start,e[i].y_end,e[i].z_bian); return 0; } /* 6 9 2 4 11 3 5 13 4 6 3 5 6 4 2 3 6 4 5 7 1 2 1 3 4 9 1 3 2 结果: 19 */
普里姆算法
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int INF=2139062143; int dis[5005],F[5005][5005]; bool book[5005]; int main() { memset(F,0x7f,sizeof(F)); memset(dis,0x7f,sizeof(dis)); memset(book,0,sizeof(book)); int N=0,M=0; scanf("%d%d",&N,&M); for(int i=1;i<=M;i++) { int x=0,y=0,z=0; scanf("%d%d%d",&x,&y,&z); F[x][y]=min(F[x][y],z); F[y][x]=min(F[y][x],z); } dis[1]=0; for(int i=1;i<=N;i++) { int k=0,Min=INF; for(int j=1;j<=N;j++) if(!book[j]&&dis[j]<Min) { k=j; Min=dis[j]; } book[k]=true; for(int j=1;j<=N;j++) if(!book[j]&&F[k][j]<dis[j]) dis[j]=F[k][j]; } int Ans=0; for(int i=1;i<=N;i++) if(dis[i]==INF) { printf("orz"); return 0; } else Ans+=dis[i]; printf("%d",Ans); return 0; }
洛谷模板 : P1726 上白泽慧音(Tarjan算法求强联通分量)
//Tarjan 求解有向图强连通分量的线性时间的算法 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Edge//边集数组 { int end; int last; }E[100005]; struct stack//栈 { int top; int s[5005]; }s; struct The_Answer//存储答案 { int sum; int node[5005]; }ans; The_Answer compare(The_Answer x,The_Answer y)//比较答案 { if(x.sum>y.sum) return x; if(x.sum<y.sum) return y; for(int i=1;i<=x.sum;i++) { if(x.node[i]<y.node[i]) return x; if(x.node[i]>y.node[i]) return y; } } int N=0,M=0,k=0,index_=0,DFN[5005],LOW[5005],note[5005]; bool book[5005]; void dfs(int x) { DFN[x]=LOW[x]=++index_;//初始化x的编号和它的祖先 s.s[++s.top]=x;//将x入栈 book[x]=true;//标记x已在栈中 for(int i=note[x];i!=0;i=E[i].last)//遍历以x为起点的有向边 if(!DFN[E[i].end])//如果这个点未到达过 { dfs(E[i].end);//去这个点找这个点得祖先 LOW[x]=min(LOW[x],LOW[E[i].end]);//并认这个点的祖先为祖先 } else if(book[E[i].end]) LOW[x]=min(LOW[x],DFN[E[i].end]);//否则,如果这个点已在栈中,就认这个点为祖先 if(DFN[x]==LOW[x])//如果x自己是自己的祖先,就说明找到了一个强连通图 { The_Answer T; T.sum=0; do{//存储答案 T.node[++T.sum]=s.s[s.top]; book[s.s[s.top]]=false; s.top--;//结点出栈 }while(x!=s.s[s.top+1]); sort(T.node+1,T.node+T.sum+1);//排序 ans=compare(ans,T);//比较答案 } return; } int main() { s.top=0;//初始化 memset(DFN,0,sizeof(DFN)); memset(LOW,0,sizeof(LOW)); memset(note,0,sizeof(note)); memset(book,0,sizeof(book)); scanf("%d%d",&N,&M); for(int i=1;i<=M;i++) { int a=0,b=0,t=0; scanf("%d%d%d",&a,&b,&t); k++;//存边 E[k].end=b; E[k].last=note[a]; note[a]=k; if(t==2)//无向图就再存一遍 { k++; E[k].end=a; E[k].last=note[b]; note[b]=k; } } ans.sum=0; for(int i=1;i<=N;i++)//如果有结点没遍历到就接着遍历 if(!DFN[i]) dfs(i); printf("%d ",ans.sum);//输出答案 for(int i=1;i<=ans.sum;i++) printf("%d ",ans.node[i]); return 0; }
洛谷模板:P3379 【模板】最近公共祖先(LCA)(Tarjan离线算法)
//Tarjan-LCA #include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; struct ask//存储询问 { int another,next; }Q[1000005]; struct Edge//存储边 { int end,next; }E[1000005]; int N=0,M=0,S=0,T1=0,T2=0,k_1=0,k_2=0,ans[500005],F[500005],Note[500005],Book[500005]; bool vis[500005]; void connect_A(int x,int y)//存边 { k_1++; E[k_1].end=y; E[k_1].next=Note[x]; Note[x]=k_1; return; } void connect_B(int x,int y)//存询问 { k_2++; Q[k_2].another=y; Q[k_2].next=Book[x]; Book[x]=k_2; return; } int find(int x)//并查集找祖先 { if(F[x]==x) return x; return F[x]=find(F[x]); } void dfs(int x) { F[x]=x;//初始化,自己是自己的祖先 vis[x]=true;//标记,表示这个点已访问过 for(int i=Note[x];i!=0;i=E[i].next)//遍历这个点的每一条边 if(!vis[E[i].end])//如果这一条边的终点还没有被访问过 { dfs(E[i].end);//访问 F[find(E[i].end)]=find(x);//合并 } for(int i=Book[x];i!=0;i=Q[i].next)//遍历有关于这个点的询问 if(vis[Q[i].another])//如果询问中的另一个点已被访问,答案即为另一个点的祖先 if(i%2) ans[(i+1)/2]=find(Q[i].another);//因为是双向存储,所以要还原 else ans[i/2]=find(Q[i].another); return; } int main() { scanf("%d%d%d",&N,&M,&S); for(int i=1;i<N;i++) { scanf("%d%d",&T1,&T2); connect_A(T1,T2);//存边存两次 connect_A(T2,T1); } for(int i=1;i<=M;i++) { scanf("%d%d",&T1,&T2); connect_B(T1,T2);//存询问也要存两次 connect_B(T2,T1); } dfs(S);//Tarjan for(int i=1;i<=M;i++) printf("%d ",ans[i]);//输出 return 0; }
数据模板:随机生成树的对拍数据
//随机生成树的对拍数据,利用并查集 #include<iostream> #include<cstdlib> #include<ctime> using namespace std; int F[500005]; int find(int x) { if(F[x]==x) return x; return F[x]=find(F[x]); } void merge(int x,int y) { int T1=find(x),T2=find(y); if(T1!=T2) F[T2]=T1; } int main() { srand(time(NULL)); int N=10000,M=1,S=rand()%N+1; cout<<N<<" "<<M<<" "<<S<<endl; for(int i=1;i<=N;i++) F[i]=i; for(int i=1;i<N;i++) { int x=1,y=1; while(x==y||find(x)==find(y)) x=rand()%N+1,y=rand()%N+1; cout<<x<<" "<<y<<endl; merge(x,y); } for(int i=1;i<=M;i++) cout<<rand()%N+1<<" "<<rand()%N+1<<endl; return 0; }
洛谷模板:P3865 【模板】ST表 P1816 忠诚
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int A[100005],F[100005][20];//F[i][j]表示从i开始连续2^j个数的最大值 int main() { int N=0,M=0; scanf("%d%d",&N,&M); for(int i=1;i<=N;i++) { scanf("%d",&A[i]); F[i][0]=A[i];//初始化,从i开始连续2^0个数的最大值就是A[i] } //dp预处理 for(int j=1;(1<<j)<=N;j++) for(int i=1;i+(1<<j)-1<=N;i++) F[i][j]=max(F[i][j-1],F[i+(1<<(j-1))][j-1]);//每个区间都从两个平分的区间中取最大值 //这里把j放在外层循环而把i放在内层循环是因为每一个区间的最大值都是从两个较小的区间的最大值得来的, //我们应该从小到大地计算区间,而不是按从前到后地计算区间 //查询 for(int i=1;i<=M;i++) { int L=0,R=0,Len=0; scanf("%d%d",&L,&R); Len=int(log2(R-L+1)); printf("%d ",max(F[L][Len],F[R-(1<<Len)+1][Len]));//查找最大值 } return 0; }
洛谷模板:P3370 【模板】字符串哈希
1、再哈希
#include<iostream> #include<cstdio> #include<vector> using namespace std; const int ln=1000007; string Hash[ln]; int Hash_function_1(string st)//哈希函数1 { int len=st.size(),number=0; for(int i=0;i<len;i++) number+=int(st[i])+i; return number%ln; } int Hash_function_2(string st)//哈希函数2 { int len=st.size(),number=1; for(int i=0;i<len;i++) number=(number%ln)*((int(st[i])+i)%ln)%ln; return number; } int Hash_function_3(string st)//哈希函数3 { int len=st.size(),number=1; for(int i=0;i<len;i++) number=(number%ln)*((int(st[i])-i)%ln)%ln; return number; } int main() { ios::sync_with_stdio(false); int N=0,Ans=0; cin>>N; for(int i=1;i<=N;i++) { string T=""; cin>>T; int num=Hash_function_1(T); if(Hash[num]=="")//不断调用哈希函数,直到没有冲突为止 { Hash[num]=T; Ans++; } else if(Hash[num]!=T) { num=Hash_function_2(T); if(Hash[num]=="") { Hash[num]=T; Ans++; } else if(Hash[num]!=T) { num=Hash_function_3(T); if(Hash[num]=="") { Hash[num]=T; Ans++; } } } } cout<<Ans; return 0; }
2、链地址
#include<iostream> #include<cstdio> #include<vector> using namespace std; vector<string> Hash[1307255]; int Hash_function(string st)//哈希函数 { int len=st.size(),number=0; for(int i=0;i<len;i++) number+=int(st[i])+i; return number; } int main() { ios::sync_with_stdio(false); int N=0,Ans=0; cin>>N; for(int i=1;i<=N;i++) { string T=""; cin>>T; int num=Hash_function(T),len=Hash[num].size(); bool flag=false; for(int j=0;j<len;j++)//存储 if(Hash[num][j]==T) { flag=true; break; } if(!flag)//如果没有发生冲突,答案++ { Hash[num].push_back(T); Ans++; } } cout<<Ans; return 0; }
3、开放地址
#include<iostream> #include<cstdio> #include<vector> using namespace std; string Hash[1307255]; int Hash_function(string st)//哈希函数 { int len=st.size(),number=0; for(int i=0;i<len;i++) number+=int(st[i])+i; return number; } int main() { ios::sync_with_stdio(false); int N=0,Ans=0; cin>>N; for(int i=1;i<=N;i++) { string T=""; cin>>T; int num=Hash_function(T); if(Hash[num]=="")//如果此位置为空 { Hash[num]=T;//就存储 Ans++; } else if(Hash[num]!=T)//如果发生冲突 for(int j=num+1;;j++)//就往后找空位 { if(j==1307255) j=0; if(Hash[j]==T) break; if(Hash[j]=="") { Hash[j]=T; Ans++; break; } } } cout<<Ans; return 0; }
4、公共溢出
#include<iostream> #include<cstdio> #include<vector> using namespace std; string Hash[1307255],Public[10005]; int Hash_function(string st)//哈希函数 { int len=st.size(),number=0; for(int i=0;i<len;i++) number+=int(st[i])+i; return number; } int main() { ios::sync_with_stdio(false); int N=0,Ans=0; cin>>N; for(int i=1;i<=N;i++) { string T=""; cin>>T; int num=Hash_function(T); if(Hash[num]=="")//如果此位置为空 { Hash[num]=T;//就存储 Ans++; } else if(Hash[num]!=T)//如果发生冲突 for(int j=0;j<10005;j++)//就存入公共溢出区 { if(Public[j]==T) break; if(Public[j]=="") { Public[j]=T; Ans++; break; } } } cout<<Ans; return 0; }
5、map
//字符串哈希:map方法 #include<iostream> #include<cstdio> #include<vector> #include<map> using namespace std; map<string,bool> book; int main() { ios::sync_with_stdio(false); int N=0,Ans=0; cin>>N; for(int i=1;i<=N;i++) { string T=""; cin>>T; if(!book[T]) { Ans++; book[T]=true; } } cout<<Ans; return 0; }
6、set
//字符串哈希:SET方法 #include<iostream> #include<cstdio> #include<vector> #include<set> using namespace std; set<string> s; int main() { ios::sync_with_stdio(false); int N=0; cin>>N; for(int i=1;i<=N;i++) { string T=""; cin>>T; s.insert(T); } cout<<s.size(); return 0; }
洛谷模板:P3378 【模板】堆(手打)
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int p=0,s[1000005];//s表示小根堆按层遍历的序列 void cr(int x)//插入x到堆中 { p++; s[p]=x;//将x置于序列末尾 int now=p,par=p/2;//now表示x在序列中的位置,par表示x的父节点在序列中的位置 while(par>0&&s[par]>s[now])//如果此时的x不为根节点并且它的父节点小于它 { swap(s[par],s[now]);//就把x和它的父节点交换 par/=2;//更新位置 now/=2; } return; } void del()//删除堆顶元素 { s[1]=s[p--];//将堆顶元素替换为序列最末尾的元素,方便处理 int now=1,son=0;//now表示此元素在序列中的位置,son表示此元素左右儿子中较小的一个在序列中的位置 while(now*2<=p)//如果此元素不为叶子节点 { son=now*2;//计算其左儿子位置 if(son<p&&s[son]>s[son+1]) son++;//在左右儿子中取较小的一个 if(s[now]<s[son]) break;//如果此元素比它的左右儿子都要小,就不用继续交换了,退出 swap(s[now],s[son]);//否则交换它们的值 now=son;//更新位置 } return; } int main() { int n=0; scanf("%d",&n); for(int i=1;i<=n;i++) { int t=0; scanf("%d",&t); if(t==1)//插入 { int e=0; scanf("%d",&e); cr(e); } if(t==2) printf("%d ",s[1]);//输出最小元素,即堆顶元素 if(t==3) del();//删除最小元素,即堆顶元素 } return 0; }
洛谷模板:P1177 【模板】快速排序(手打)
//洛谷快排AC版本 #include<iostream> #include<cstdio> #include<cstdlib> #include<ctime> using namespace std; int N=0,A[100005]; void qsort(int l,int r)//快排 { if(l>=r) return;//如果处理完毕就结束 int L=l,R=r,key=A[(l+r)/2];//key为基准数,取中间数速度更块 while(L<=R)//将所有小于key的数放在左边,所有大于key的数放在右边 { while(A[L]<key) L++;//从左往右找一个大于等于key的数 while(A[R]>key) R--;//从右往左找一个小于等于key的数 if(L<=R) { swap(A[L],A[R]);//交换 L++; R--; } } qsort(l,R);//接着处理左边的区间 qsort(L,r);//接着处理右边的区间 } int main() { scanf("%d",&N); for(int i=1;i<=N;i++) scanf("%d",&A[i]); qsort(1,N); for(int i=1;i<=N;i++) printf("%d ",A[i]); return 0; }