目录spa
本文将记录一些奇技淫巧和板子(最基础的也有),先从今天开始写,之前的找个时间再补上code
应用快速排序思想(\(O(n)\)),日常都是\(O(nlogn)\)
基于快排的思想,在每一层递归中,随机选取一个数作基准时,统计出大于基准值的数的个数\(cnt\),若是\(k<=cnt\)就在左半段(比基准数大)中寻找第\(k\)大的数,反之则在右半段寻找第\(k-cnt\)大的数排序
复杂度证实:递归
由于每次只进入了左右两段的任意一个,则在平均状况之下复杂度为:\(n+\frac{n}{2}+\frac{n}{3}+.....+1=O(n)\)it
预处理class
void st_prework() { for(int i=1; i<=n; ++i) f[i][0]=a[i]; for(int j=1; j<=21; ++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]); }
查询基础
int query(int l,int r) { int res=-9999; int k=0; while((1<<(k+1)<=r-l+1)) k++; res=max(f[l][k],f[r-(1<<k)+1][k]); return res; }
开两个栈,a存原始数据,b存历史上每一个时刻的最小值
举个例子
a:9 2 1 5 3 0 2 <-
b:9 2 1 1 1 0 0 <-
每次插入元素x时,a插入x,b插入min(top(b),x),弹出时一块儿弹,询问时输出top(b)遍历
以前用的二分太傻比了,须要考虑的东西太多(但是我没有脑子),学长就教了一个咕咕咕的二分queue
int l=0,r=1e18;//取个大一点的数 while(l<=r) { int mid=(l+r)>>1; if(check(mid)) r=mid-1,ans=mid; else l=mid+1; } cout<<ans;
double l=0,r=1e18;//取个大一点的数 while(r-l<=eps) { double mid=(l+r)/2; if(check(mid)) r=mid,ans=mid; else l=mid; } cout<<ans;
//dfs void dfs(int x) { visit[x]=1; for(int i=head[x];i;i=e[i].Next) { int to=e[i].v; if(visit[to]) continue; dfs(to); } } //bfs void bfs() { queue<int>q; q.push(1); d[1]=1;//层数 while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].Next) { int to=e[i].v; if(visit[to]) continue; d[to]=d[u]+1; q.push(to); } } }
dfs序的特色:统计
每一个节点x编号在序列中出现两次,并且以这两次出现位置为端点的闭区间就是以x为根的子树的DFS序
void dfs(int x) { a[++len]=x;//记录dfs序 visit[x]=1; for(int i=head[x];i;i=e[i].Next) { int to=e[i].v; if(visit[to]) continue; dfs(to); } a[++len]=x; }
void dfs(int x) { int max_part=0;//删除掉x后最大子树大小 size[x]=1;//子树x的大小 visit[x]=1; for(int i=head[x];i;i=e[i].Next) { int to=e[i].v; if(visit[to]) continue; dfs(to); size[x]+=size[y]; max_part=max(max_part,size[y]); } max_part=max(max_part,n-size[x]);//n为整颗树的节点数目 if(max_part<ans) { ans=max_part;//记录重心对应的max_part值 pos=x;//记录重心编号 } }
void dfs(int x) { visit[x]=cnt; for(int i=head[x];i;i=e[i].Next) { int to=e[i].v; if(visit[to]) continue; dfs(to); } } for(int i=1;i<=n;++i) if(!visit[i]) cnt++,dfs(i);
void topsort() { queue<int>q; for(int i=1;i<=n;++i) if(du[i]==0) q.push(i);//du在add时记录 while(!q.empty()) { int u=q.front(); q.pop(); a[++len]=u;//记录拓扑序 for(int i=head[u];i;i=e[i].Next) { int to=e[i].v; if(--du[to]==0) q.push(to); } } }
int * z=y+50 z[50]-->y[0]