数据结构

(如果有的话) 读者请先看底部说明

1.并查集

并查集是一种能够判断两个元素是否属于同一个集合的数据结构,主要有操作有:将两个集合合并;查询一个元素所在的集合。

查询:

int fid(int x){
	if(fa[x]==x) return x;
	return fa[x]=fid(fa[x]);
}

合并

void merge(int x,int y){
	x=fa[x],y=fa[y];
	if(x==y) return;
	fa[x]=y;
} 

2.线段树

(1).基础

(2).扫描线

_1.求面积

首先将点离散化。将每一根线段用线段树上的一个点表示,线段树上的每一个点代表的线段都是右端点减去左端点,注意叶子节点不能产生贡献。最后按线段的高度排序,并加上标签。

_2.特殊意义的扫描线

可以处理除去~~的贡献的问题。

同样将每根线段的左右端点单独列出来,并打上标签,类似于高度按照某个量排序。

_3.李超线段树

P4097

李超线段树用于解决:在平面直角坐标系中插入线段,问一个在哪一条线段上取到最大的

原理:两条线段最多只有一个交点,根据这点,对一个区间,李超线段树只维护在该区间内在大多数时候最大(表现为该线段在当前区间处的比其它线段都大)的线段,而反常的时候怎么办呢?由于两条线段最多只有一个交点,反常的位置只能在左或右的一段,那么向下递归更新反常的那一段即可,直到确定每一段区间的大多数时候最大的线段。查询时,由于是单点查询,可以直接递归到底。由于和其它线段树不同,该线段树只维护大多数时候正确的那个答案,所以一定要递归到底,且要在每一层都取

代码:

#include<bits/stdc++.h>
using namespace std;
int m,ans,tot;
const int inf=1e9+7;
const double eps=1e-10;
struct o{
	int xma,xmi;
	double k,b;
	double operator ()(int x){
		if(x<=xma&&x>=xmi) return  1.0*(k*x+b);
		return -inf;
	}
}a[5000100];
struct oo{
	int tree[5000100];
	pair<double,int> ma(pair<double,int>a,pair<double,int>b ){
		if(a.first-b.first>eps) return a;
		if(b.first-a.first>eps) return b;
		return a.second<b.second?a:b;
	}
	int ls(int k){return k<<1;}
	int rs(int k){return k<<1|1;}
	void change(int k,int l,int r,int x,int y,int v){
		if(x<=l&&y>=r){
			if(!tree[k]){
				tree[k]=v;
				return;
			}
			int mid=(l+r)>>1;
			if(a[v](mid)-a[tree[k]](mid)>eps) swap(v,tree[k]);
			
			if(a[v](l)-a[tree[k]](l)>eps||(fabs(a[v](l)-a[tree[k]](l))<=eps&&v<tree[k])) change(ls(k),l,mid,x,y,v);
			if(a[v](r)-a[tree[k]](r)>eps||(fabs(a[v](r)-a[tree[k]](r))<=eps&&v<tree[k])) change(rs(k),mid+1,r,x,y,v);
			return;
		}
		int mid=(l+r)>>1;
		if(x<=mid) change(ls(k),l,mid,x,y,v);
		if(y>mid) change(rs(k),mid+1,r,x,y,v);
		return;
	}
	pair<double,int> ask(int k,int l,int r,int x){
		pair<double,int>res;
		if(tree[k]) res=make_pair(a[tree[k]](x),tree[k]);
		if(l==r){
			return res;
		}
		int mid=(l+r)>>1;
		if(x<=mid) res=ma(ask(ls(k),l,mid,x),res);
		else res=ma(ask(rs(k),mid+1,r,x),res);
		return res;
	}
}t;
int read(){
	char ch=getchar();int x=0,f=1;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
int main(){
	m=read();
	while(m--){
		int op=read();
		if(op){
			int x0=read(),y0=read();
			int x1=read(),y1=read();
			x0=(x0+ans-1)%39989+1;
			y0=(y0+ans-1)%(1000000000)+1;
			x1=(x1+ans-1)%39989+1;
			y1=(y1+ans-1)%(1000000000)+1;
			if(x1==x0){
				++tot;
				a[tot].xma=a[tot].xmi=x1;
				a[tot].b=max(y1,y0);
				a[tot].k=0;
			}else{
				a[++tot].xma=max(x1,x0);
				a[tot].xmi=min(x1,x0);
				a[tot].k=1.0*(y0-y1)/(x0-x1);
				a[tot].b=1.0*(1.0*y1-1.0*a[tot].k*x1);
			}
			t.change(1,1,39990,min(x1,x0),max(x1,x0),tot);
		}else{
			int x=read();x=(x+ans-1)%39989+1;
			ans=t.ask(1,1,39990,x).second;
			printf("%d\n",ans);
		}
	}
	return 0;
} 

当然李超线段树也可以维护区间最值:

P4069

代码:

#include<bits/stdc++.h>
using namespace std;
long long dis[1000100],atid[1000100],e,head[1000100],dep[1000100],siz[1000100],fa[1000100],son[1000100];
long long top[1000100],id[1000100],dfn,n,m,tot;
const long long inf=123456789123456789;
struct o{
	long long ne,to,w;
}a[1000100];
struct oo{
	long long xma,xmi,k,b;
	long long operator ()(long long x){
		return k*x+b;
	}
}g[1000100];
struct ooo{
	long long tree[1000100],mi[1000100];
	void init(){
		for(long long i=0;i<=1000000;i++){
			mi[i]=inf;
		}
	}
	long long ls(long long k){return k<<1;}
	long long rs(long long k){return k<<1|1;}
	void change(long long k,long long l,long long r,long long x,long long y,long long v){
		if(x<=l&&y>=r){
			mi[k]=min(mi[k],min(g[v](dis[atid[l]]),g[v](dis[atid[r]])));//维护答案 
			long long mid=(l+r)>>1; 
			if(g[v](dis[atid[mid]])<g[tree[k]](dis[atid[mid]])){
				swap(v,tree[k]);//维护大多数时候最优的  注意答案不能用mid更新
			}
			if(l==r) return;
			if(g[v](dis[atid[l]])<g[tree[k]](dis[atid[l]])) change(ls(k),l,mid,x,y,v);
			if(g[v](dis[atid[r]])<g[tree[k]](dis[atid[r]])) change(rs(k),mid+1,r,x,y,v);
			mi[k]=min(mi[k]/*不要忘了和自己比较*/,min(mi[ls(k)],mi[rs(k)]));//
			return;
		}
		long long mid=(l+r)>>1;
		if(x<=mid) change(ls(k),l,mid,x,y,v);
		if(y>mid) change(rs(k),mid+1,r,x,y,v);
		mi[k]=min(mi[k],min(mi[ls(k)],mi[rs(k)]));//
	}
	long long ask(long long k,long long l,long long r,long long x,long long y){
		if(x<=l&&y>=r){
			return mi[k];
		}
		long long mid=(l+r)>>1,res=min(g[tree[k]](dis[atid[max(l,x)]]),g[tree[k]](dis[atid[min(r,y)]]));//
		if(x<=mid) res=min(res,ask(ls(k),l,mid,x,y));
		if(y>mid) res=min(res,ask(rs(k),mid+1,r,x,y));
		return res;
	}
}t;
void dd(long long u,long long v,long long w){
	a[++e].ne=head[u];
	a[e].to=v;
	a[e].w=w;
	head[u]=e;
}
void dfs1(long long x,long long f){
	dep[x]=dep[f]+1;
	siz[x]=1;
	fa[x]=f;
	for(long long i=head[x];i;i=a[i].ne){
		long long v=a[i].to;
		if(v==f) continue;
		dis[v]=dis[x]+a[i].w;
		dfs1(v,x);
		siz[x]+=siz[v];
		if(!son[x]||siz[son[x]]<siz[v]) son[x]=v;
	}
}
void dfs2(long long x,long long tp){
	top[x]=tp;
	id[x]=++dfn;
	atid[dfn]=x;
	if(!son[x]) return;
	dfs2(son[x],tp);
	for(long long i=head[x];i;i=a[i].ne){
		long long v=a[i].to;
		if(v==fa[x]||v==son[x]) continue;
		dfs2(v,v);
	}
}
long long lca(long long x,long long y){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}
long long getdis(long long x,long long y){
	return dis[x]+dis[y]-(dis[lca(x,y)]<<1);
}
void change(long long x,long long y,long long v){
	while(top[x]!=top[y]){
		t.change(1,1,n,id[top[x]],id[x],v);
		x=fa[top[x]];
	}
	t.change(1,1,n,id[y],id[x],v);
}
long long ask(long long x,long long y){
	long long res=inf;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		res=min(res,t.ask(1,1,n,id[top[x]],id[x]));
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	res=min(res,t.ask(1,1,n,id[x],id[y]));
	return res;
}
long long read(){
	char ch=getchar();long long x=0,f=1;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
int main(){
	n=read();m=read();
	for(long long i=1;i<n;i++){
		long long u=read(),v=read(),w=read();
		dd(u,v,w);dd(v,u,w);
	}
	t.init();
	dfs1(1,0);dfs2(1,1);
	g[0].b=inf; //
	while(m--){
		long long op=read(),x=read(),y=read();
		if(op==1){
			long long k=read(),b=read();
			long long anc=lca(x,y);
			g[++tot].k=-k;
			g[tot].b=k*dis[x]+b;
			g[tot].xma=dis[x];
			g[tot].xmi=dis[anc];
			change(x,anc,tot);
			g[++tot].k=k;
			g[tot].b=b+k*dis[x]-2*k*dis[anc];
			g[tot].xma=dis[y];
			g[tot].xmi=dis[anc];
			change(y,anc,tot);
		}else{
			printf("%lld\n",ask(x,y));
		}
	}
	return 0;
} 

可以和斜率优化结合:

P4655

转移显然有:

暴力,考虑优化。

先把平方展开:

因为我们肯定是从推到,所以把当成已知量处理,整理得到:

因为是从枚举的,所以是变化的。显然对于每一个,把看成自变量,都有一个关于的函数。这样就是李超线段树的模板题了。

代码:

#include<bits/stdc++.h>
using namespace std;
long long h[1000100],w[1000100],sum[1000100],tot;
struct oo{
	long long k,b;
	long long operator ()(long long x){
		return k*x+b;
	}
}a[1000100];
struct o{
	long long tree[8000100];
	long long ls(long long k){return k<<1;}
	long long rs(long long k){return k<<1|1;}
	void change(long long k,long long l,long long r,long long x,long long y,long long v){
		if(x<=l&&y>=r){
			long long mid=(l+r)>>1;
			if(a[v](mid)<a[tree[k]](mid)) swap(v,tree[k]);
			if(l==r) return;
			if(a[v](l)<a[tree[k]](l)) change(ls(k),l,mid,x,y,v);
			if(a[v](r)<a[tree[k]](r)) change(rs(k),mid+1,r,x,y,v);
			return;
		}
		long long mid=(l+r)>>1;
		if(x<=mid) change(ls(k),l,mid,x,y,v);
		if(y>mid) change(rs(k),mid+1,r,x,y,v);
	}
	long long ask(long long k,long long l,long long r,long long x){
		if(l==r){
			return a[tree[k]](l);
		}
		long long mid=(l+r)>>1;
		long long res=a[tree[k]](x);
		if(x<=mid) res=min(res,ask(ls(k),l,mid,x));
		else res=min(res,ask(rs(k),mid+1,r,x));
		return res;
	}
}t; 
long long read(){
	char ch=getchar();long long x=0,f=1;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
long long pf(long long x){return x*x;}
int main(){
	int n=read();
	for(int i=1;i<=n;i++) h[i]=read();
	for(int i=1;i<=n;i++){
		long long x=read();sum[i]=sum[i-1]+x;
	}
	a[0].b=1e18+7;
	a[++tot].k=-2*h[1];
	a[tot].b=pf(h[1])-sum[1];
	t.change(1,0,1000000,0,1000000,tot);
	for(int i=2;i<n;i++){
		long long x=t.ask(1,0,1000000,h[i])+pf(h[i])+sum[i-1];
		a[++tot].k=-2*h[i];
		a[tot].b=pf(h[i])-sum[i]+x;
		t.change(1,0,1000000,0,1000000,tot);
	} 
	printf("%lld\n",t.ask(1,0,1000000,h[n])+pf(h[n])+sum[n-1]);
	return 0;
} 

_4.可持久化线段树

@1基础

先看最简单的场景:对一个序列,每次更新只修改一个数,并把新序列当作一个新的版本。要查询某个版本序列的区间和。如果只保留最后版本的话很容易想到用线段树维护。但现在要维护多个版本,最简单的线段树已经不能达到目标了。思考一下,每次只改一个数,那么序列每次的变化其实是很小的,如果用线段树维护的话,不需要对整个序列重新建立一棵完整的线段树,只维护变化的节点就行了。根据这个思路,我们就可以创造出可持久化线段树了。

具体是这样操作的:每次修改,沿途新建,其余复制。在经典线段树上,每次修改都会有一个树上路径,由于新版本的线段树和旧版本的不一样,但又不能覆盖旧版本,所以沿途的每个节点都要新建。根据之前的思路,新节点的大部分信息与旧节点相同,所以可以先复制旧节点信息,只修改不同的部分。具体见代码:

int change(int pre,int l,int r,int x,int v){
	int k=++tot;
	tree[k]=tree[pre];
	if(l==r){
		tree[k].sum=v;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) tree[k].ls=change(tree[pre].ls,l,mid,x,v);
	else tree[k].rs=change(tree[pre].rs,mid+1,r,x,v);
	tree[k].sum=tree[tree[k].ls].sum+tree[tree[k].rs].sum;
	return k;
} 

不难发现一次修改最多修改个节点,时间复杂度、空间复杂度均为

那么区间修改、新建版本呢?其实也是可以的。由于懒标记的存在,我们可以积蓄修改操作,直到需要的时候再下传。主要操作依旧是沿途修改,其余复制,有些不同的是,在下传操作时也需要新建节点(因为下传之后信息发生变化,而旧节点可能仍在某个版本中需要被复用,所以需要新节点维护),但如果是在修改操作时下传,在下传之后立马就要修改,那么刚刚新建的节点可能就直接被浪费了。但其实这不要紧,即使有浪费的情况,一次修改消耗的空间依然是级别的,总空间复杂度为,浪费只会加常数,不影响算法的正确性。

模板题:

SP11470

代码:

#include<bits/stdc++.h>
using namespace std;
long long n,q,a[1000100],tot,rt[1000100];
struct o{
	long long ls,rs,sum,lan;
}tree[10000100];
long long clone(long long v){
	long long k=++tot;
	tree[k]=tree[v];
	return k;
}
void pup(long long k){
	tree[k].sum=tree[tree[k].ls].sum+tree[tree[k].rs].sum;
}
void build(long long &k,long long l,long long r){
	if(!k) k=++tot;
	if(l==r){
		tree[k].sum=a[l];
		return;
	}
	long long mid=(l+r)>>1;
	build(tree[k].ls,l,mid);
	build(tree[k].rs,mid+1,r);
	pup(k);
}
void add(long long k,long long l,long long r,long long v){
	tree[k].sum+=(r-l+1)*v;
	tree[k].lan+=v; 
}
void pud(long long k,long long l,long long r,long long mid){
	if(tree[k].lan){
		tree[k].ls=clone(tree[k].ls);
		tree[k].rs=clone(tree[k].rs);
		add(tree[k].ls,l,mid,tree[k].lan);
		add(tree[k].rs,mid+1,r,tree[k].lan);
		tree[k].lan=0;
	}
}
long long change(long long pre,long long l,long long r,long long x,long long y,long long v){
	long long k=clone(pre); 
	if(x<=l&&y>=r){
		add(k,l,r,v);
		return k;
	}
	long long mid=(l+r)>>1;
	pud(k,l,r,mid);
	if(x<=mid) tree[k].ls=change(tree[k].ls,l,mid,x,y,v);
	if(y>mid) tree[k].rs=change(tree[k].rs,mid+1,r,x,y,v);
	pup(k);
	return k;
}
long long ask(long long k,long long l,long long r,long long x,long long y){
	if(x<=l&&y>=r){
		return tree[k].sum;
	}
	long long mid=(l+r)>>1,res=0;
	pud(k,l,r,mid);
	if(x<=mid) res=ask(tree[k].ls,l,mid,x,y);
	if(y>mid) res+=ask(tree[k].rs,mid+1,r,x,y);
	return res;
}
long long read(){
	char ch=getchar();long long x=0,f=1;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
int main(){
	n=read();q=read();
	for(long long i=1;i<=n;i++) a[i]=read();
	build(rt[0],1,n);
	long long t=0;
	while(q--){
		char op;cin>>op;
		long long x=read();
		if(op=='C'){
			long long y=read(),z=read();
			rt[t+1]=change(rt[t],1,n,x,y,z);
			++t;
		}else if(op=='Q'){
			long long y=read();
			printf("%lld\n",ask(rt[t],1,n,x,y));
		}else if(op=='H'){
			long long y=read(),z=read();
			printf("%lld\n",ask(rt[z],1,n,x,y));
		}else{
			t=x;
		}
	}
	return 0;
} 

@2经典应用

最基本的就是版本问题,即:修改但不抛弃,即我不仅会用到修改后的,修改前的我也会用到。

另一种就是可以把可持久化值域线段树当成前缀和处理。

即:除了版本问题,还有就是特殊的区间问题了,通常与“一个数在某个区间出现了多少次”有关(比如区间第小是谁)。这时就可以建立可持久化值域线段树了。每插入一个值都当作是对原序列修改产生的一个新的版本,这样就可以用类似前缀和的方式去处理线段树上节点了。本质是:在版本上的出现次数版本上的出现次数就是区间的出现次数。值域线段树上每个节点可以维护区间内所有数的出现次数之和,这样就很好处理了。

3.树状数组

4.分块

易错点

一定要考虑左右端点在同一个块内的情况,要特殊处理!!!

正文

分块就是将暴力做法放到一个块里面处理。询问时,两边的散块可以暴力处理,中间的整块可以非常快速地得到答案,从而将时间复杂度降到

经验而言,块内对问题的答案是一定要维护的。

经典套路:

(1).带单点修改;找一段区间有多少数大于

新创建一个数组,用来存储一个块内的升序顺序。

询问:对散块直接暴力处理,整块用在块内数组快速查询,时间复杂度

修改:单点直接单个元素冒泡排序。如果是区间修改,尽量不要使用,很慢,可以观察一些性质来处理。

总复杂度

(2).求区间众数(具体到是哪一个数)(不带修改)

维护为块的众数,为前个块中的出现次数。那么对一个询问,答案只可能为:散块里面出现过的数,中间整块的众数,数量是级别的,直接暴力枚举可能的答案,时间复杂度

5.莫队

根据排序对暴力进行优化的离线算法。

(1).经典莫队

按左端点所在块排序,相同则升序排序。左端点移动复杂度,右端点时间复杂度,总时间复杂度

(2).带修莫队

带修改时,多出一个变量:修改的时间。变成的三维问题。将块长调整为,按依次按左端点所在块、右端点所在块、时间升序排序。左右端点移动很好处理,时间流动时要能同时做到实现修改和消除修改的影响(通常要用到)。总时间复杂度

(3).回滚莫队

当增加操作很好处理,但删除操作异常困难的时候,就可以上回滚莫队。

因为右端点单调递增,所以只有增加操作,要删除的只有左端点。那么可以考虑让左端点也只有增加操作,那就是从左端点所在块的右端点开始向左回滚,这样就只有增加操作了,且左端点回滚的时间复杂度仍为。总时间复杂度

声明(一定要看)

虽然我的文章应该没人看但还是要说明:这篇文章的初衷是自用的,主要写给自己看以总结提高、方便复习的,对内容的正确性不做任何保证(当然大部分应该是对的),有错误可以指出

原始链接:a

全部评论

相关推荐

01-27 22:20
复旦大学 Java
大家好,我是程序员花海,今天周末,恰好有时间来和大家聊一下校招和实习的底层知识!友情提示:这边文章干货很多,建议收藏,也欢迎你的小花~我讲结合自己担任校招面试官多年的经验,从校招笔试、校招面试、选择Offer、提前入职、实习转正、试用期Landing等众多角度来一一为大家拆解校招的底层逻辑,话不多说,现在开讲!在准备校招面试的时候,大家可能会参考很多学长学姐的建议,但是你听到的的建议五花八门,比如有鹅选鹅、无鹅延毕,但是大家仔细想想,这句话真的对吗?首先无可厚非,鹅的福利真的很好,但是这个是从公司角度来说,这个公司整体氛围不错,但是你入职之后,是要分到某一个业务部门下的某一个组的,你的Offer上面只会写你属于哪个部门,当然也不排除部分会写你是哪个组的,但是作为一名校招生,没有真实工作经验,进入之后一切工具和开发流程都要重新学,这个时候,组内各部门的对于校招的重视程度和培养计划就相当重要了,所以切记,无脑冲字节、有鹅选鹅只是个梗,不要当真哇!那么如何全方面的了解校招呢?我想从以下几个方面来和大家探讨一下,仅代表我个人观点,有不同意见的同学也可以在评论区留言,我都会一一看的。首先,你要了解校招是干什么的。首先,学长学姐的经验主要是适合他自己,比如有的同学本科研究生都是9,你的学历是双非,他说我没有实习经历一样进大厂,你就轻视了实习经历的重要性,到最后发现没实习连简历都过不了,这里面就忽视了一个重要的问题,第一,你需要有机会进入这样的实习平台去获得实习产出,这样才会在你的简历上写出很多不一样的东西。第二,实习期间确有高质量产出,且能够自圆其说。第三,面试官恰好认可这段经历足以弥补其他方面的短板。这就像问“如何考上顶尖大学”,得到的回答是“拿到学科竞赛金牌就可以了”虽然真实,却未必是普遍路径。当然也有的同学会说现在行情太差,不是竞赛选手笔试都过不了,不如早点转行。这就像劝退高考生:大学生这么多,不如读专科早早学技术。一旦我们把这些例子放到你熟悉的语境中,就能看出其局限性。因此,构建属于自己的、符合招聘现实的认知至关重要。针对自己的情况,建力一个对于校招清晰的认知,是非常关键的,同时也能够让你针对自己的情况,做一个清晰的学习规划,不至于闷头学,发现自己准备的东西和面试要求的相差甚远。第二,认清楚校招的全方面流程。校招的完整流程:简历投递-&amp;gt;笔试-&amp;gt;技术一面-&amp;gt;技术二面-&amp;gt;技术三面-&amp;gt;主管面-&amp;gt;HR面-&amp;gt;谈薪资-&amp;gt;录用审批-&amp;gt;签三方-&amp;gt;提前实习-&amp;gt;正式入职。1.简历筛选:背景是第一道门槛筛选过程通常快速直接,主要看你的背景包括你的学校背景(清北+985+211+双非)过往实习、项目。这类似于初次见面时对方会先留意你的外在条件与履历,至于内在能力,那是后续环节才展开的话题。简历的书写方式我已经讲过很多次了,也会在一些评论区提供一些建议,可以参考这篇文章。2.技术面试(技术一面-&amp;gt;技术二面-&amp;gt;技术三面-&amp;gt;主管面)不少同学认为一面考八股,二三面问项目,HR面聊人生。这种模式虽然说比较常见,但大多数情况下是你的项目或实习经历缺乏深入探讨的空间,面试官只能转向八股文的考察。如果你的实习经历扎实、有真实产出,那么每一轮都可能围绕这段经历展开追问。所以说,一面考八股,二三面问项目,HR面聊人生只适用于部分同学。对于开发岗的同学来说,决定你能否进面试的因素主要还是:学历背景+实习+项目+算法,其中从重要程度来说,学历背景&amp;gt;实习&amp;gt;项目+算法,为什么把实习放到项目前面呢?主要是瑞吉外卖、苍穹外卖、黑马头条这种项目已经烂大街了,面试官看到早就审美疲劳了,但是实习不一样,实习是经过真实上线的,且有流量,能够带来一些收益的项目。为什么我不建议写谷粒商城,我的这篇文章也写过了。对于算法,一般来说会氛围笔试和面试,面试比较简单,绝大多数情况下,Hot100都会够用,除此之外,设计模式、数据结构设计、多线程代码题也会涉及到一些。另外提一嘴,面试是ACM模式,很多同学都不知道,要么是构造输入输出,要么是硬编码。但是笔试难度同面试来说就高很多了,我之前还看过部分公司的笔试题难度甚至可以颦美icpc金牌题的难度,对于没咋刷过算法题的同学来说,看到这种题目刷不出来就太正常了。关于笔试题大概的范围,可以参考这篇文章。最终是否通过某轮面试,还要看同批候选人的整体表现。即使你发挥出色,也可能因存在更匹配的人选而排序靠后。但长期来看,扎实的准备终会体现价值,其实本质就是面试评价了,关于面试评价的考核标准,恰好我也写过了,大家可以参考下。3.HR面试HR面一般我们可以理解为意向与价值观的双重确认,HR面通常是终面,也有少数公司将其放在第一轮。不少同学认为这一环只是走流程,很少刷人。实际上,HR面同样具有筛选作用——进入此轮的人数通常多于最终录用名额,且公司不会在无意义的环节上浪费资源。HR的问题大多可归为两类:求职意向确认:你拿到offer后是否会入职?是否同时投递了其他公司?价值观匹配度:你如何看待挑战?如何与团队协作?同学或同事如何评价你?所以只要回答的不要太离谱,基本都没有啥大问题。校招的考察重点始终在动态变化,19年左右卷八股,后来卷算法,如今笔试难度已接近天花板,实习与业务匹配度的权重正持续上升。随着AI技术渗透,未来笔面试形式也可能出现新形态,从去年美团等互联网大厂就开始AI面试了,尤其是大模型发展越来越迅猛的前提下,为了防止AI辅助,双机位等笔试面试方式会层出不穷的,奉劝部分同学,不要抱侥幸心理,一旦发现真的会拉黑的!好了,今天就分享这些,希望这篇分析能为你带来启发。如果有具体问题,欢迎在评论区提出!祝大家准备顺利,收获理想&nbsp;offer!
你觉得今年秋招难吗
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务