[模板]FJOI2017赛前整理


图论

KM

时间复杂度:\(O(n^3)\).

#define N 305
int w[N][N],x[N],y[N]/*二分图左右两边的点的期望值*/,fr[N],sla[N],n;
bool vx[N],vy[N]/*每个点每轮是否被尝试匹配过*/;
inline bool match(int u){
	int tmp;vx[u]=true;
	for(int j=1;j<=n;++j){
		if(vy[j]) continue;
		tmp=x[u]+y[j]-w[u][j];
		if(!tmp){//符合要求:两边期望值之和为权值
			vy[j]=true;
			if(!fr[j]||match(fr[j])){
				fr[j]=u;return true;
			}
		} 
		else sla[j]=min(sla[j],tmp);
	} 
	return false;
}
inline int KM(){
	int tmp,ret=0;
	for(int i=1;i<=n;++i){
		x[i]=-INF;
		for(int j=1;j<=n;++j)
			x[i]=max(x[i],w[i][j]);
	}
	memset(y,0,sizeof(y)); 
	memset(fr,0,sizeof(fr));
	for(int i=1;i<=n;++i){//尝试为左侧每个点进行匹配
		for(int j=1;j<=n;++j) sla[j]=INF;
		while(true){
			memset(vx,0,sizeof(vx));
			memset(vy,0,sizeof(vy));
			if(match(i)) break;
			tmp=INF;
			for(int j=1;j<=n;++j)
				if(!vy[j]) tmp=min(tmp,sla[j]);
			for(int j=1;j<=n;++j)
				if(vx[j]) x[j]-=tmp;
			for(int j=1;j<=n;++j)
				if(vy[j]) y[j]+=tmp;
				else sla[j]-=tmp; 
		}
	}
	for(int i=1;i<=n;++i)
		ret+=w[fr[i]][i];
	return ret;
}

数据结构

splay

时间复杂度:\(O(nlogn)\).

#define N 100005
struct Splay{
	int c[2],f,siz,val,cnt;//balabala...(根据题目需要的变量) 
}tr[N];
int n,rt,cnt;
inline bool son(int u){
	return tr[tr[u].f].c[1]==u;
}
inline void ins_p(int f,int u,int c){
	tr[f].c[c]=u;tr[u].f=f;
}
inline void recnt(int u){
	tr[u].siz=tr[tr[u].c[0]].siz+tr[tr[u].c[1]].siz+tr[u].cnt;
}
inline void rotate(int u){
	int f=tr[u].f;bool c=son(u);
	if(tr[f].f) ins_p(tr[f].f,u,son(f));
	else tr[u].f=0,rt=u;
	ins_p(f,tr[u].c[c^1],c);
	ins_p(u,f,c^1);
	recnt(f);recnt(u);
}
inline void splay(int u,int rt){
	while(tr[u].f!=rt){
		if(tr[tr[u].f].f==rt) rotate(u);
		else if(son(tr[u].f)==son(u)){
			rotate(tr[u].f);rotate(u);
		}
		else{
			rotate(u);rotate(u);
		}
	}
}
inline int kth(int k)/*第k小的值*/{
	int u=rt;
	while(u){
		if(k<=tr[tr[u].c[0]].siz)
			u=tr[u].c[0];
		else{
			k-=tr[tr[u].c[0]].siz;
			if(k<=tr[u].cnt) return tr[u].val;
			k-=tr[u].cnt;u=tr[u].c[1];
		}
	}
	return u;
}
inline int near(int u,bool c){
	if(tr[u].c[c]){
		u=tr[u].c[c];c^=1;
		while(tr[u].c[c])
			u=tr[u].c[c];
		return u;
	}
	while(u&&son(u)==c) u=tr[u].f;
	return tr[u].f;
}
inline int select(int u,int v){
	u=near(u,0);v=near(v,1);
	splay(u,0);splay(v,rt);
	return tr[v].c[0];
}
inline void clear(int u){
	tr[tr[u].f].c[son(u)]=0;
	tr[u].c[0]=tr[u].c[1]=tr[u].f=0;
	tr[u].siz=tr[u].val=tr[u].cnt=0;
}
inline void del(int u,int v){
	u=select(u,v);
	int f=tr[u].f;clear(u);u=f;
	while(u){
		recnt(u);u=tr[u].f;
	}
}
inline int find(int k){
	int u=rt;
	while(u&&tr[u].val!=k)
		u=tr[u].c[k>tr[u].val];
	return u;
}
inline void insert(int k){
	int u=find(k);
	if(u){
		++tr[u].cnt;
		while(u){
			recnt(u);u=tr[u].f;
		}
		return;
	}
	u=rt;
	while(tr[u].c[k>tr[u].val])
		u=tr[u].c[k>tr[u].val];
	tr[++cnt].val=k;
	tr[cnt].siz=tr[cnt].cnt=1;
	if(!u){
		rt=cnt;recnt(rt);return;
	}
	ins_p(u,cnt,k>tr[u].val);
	splay(cnt,0);
}

LCT

时间复杂度:\(O(nlogn)\).

#define N 100005
struct LCT{
	int c[2],f,rev;
}tr[N];
int n;
stack s;
inline void down(int u){
	if(tr[u].rev){
		tr[u].rev=0;
		tr[tr[u].c[0]].rev^=1;
		tr[tr[u].c[1]].rev^=1;
		swap(tr[u].c[0],tr[u].c[1]);
	}
}
inline bool son(int u){
	return tr[tr[u].f].c[1]==u;
}
inline void ins_p(int f,int u,int c){
	tr[f].c[c]=u;tr[u].f=f;
}
inline bool isroot(int u){
	return tr[tr[u].f].c[0]!=u&&tr[tr[u].f].c[1]!=u;
}
inline void recnt(int u){
	//balabala...
}
inline void rotate(int u){
	int f=tr[u].f;bool c=son(u);
	if(isroot(f)) tr[u].f=tr[f].f;
	else ins_p(tr[f].f,u,son(f));
	ins_p(f,tr[u].c[c^1],c);
	ins_p(u,f,c^1);
	recnt(f);recnt(u);
}
inline void splay(int u){
	s.push(u);
	for(int v=u;!isroot(v);v=tr[v].f) s.push(tr[v].f);
	while(!s.empty()){
		down(s.top());s.pop();
	}
	while(!isroot(u)){
		if(isroot(tr[u].f)) rotate(u);
		else if(son(tr[u].f)==son(u)){
			rotate(tr[u].f);rotate(u);
		}
		else{
			rotate(u);rotate(u);
		}
	}
}
inline void access(int u){
	for(int lst=0;u;lst=u,u=tr[u].f){
		splay(u);tr[u].c[1]=lst;recnt(u);
	}
}
inline void makeroot(int u){
	access(u);splay(u);tr[u].rev^=1;
}
inline int findroot(int u){
	access(u);splay(u);
	while(down(u),tr[u].c[0]) u=tr[u].c[0];
	splay(u);
	return u;
} 
inline void select(int u,int v){
	makeroot(u);access(v);splay(v);//u为v的左孩子 
}
inline void link(int u,int v){
	makeroot(u);tr[u].f=v; 
}
inline void cut(int u,int v){
	select(u,v);tr[v].c[0]=tr[u].f=0;recnt(v); 
}

Dsu on tree

时间复杂度:\(O(nlogn)\).

#define N 100005
struct graph{
	int nxt,to;
}e[N<<1]; 
int g[N],w[N],t[N],fa[N],son[N],ans[N];
bool big[N];
inline void add(int u,int del){
	++t[w[u]];
	if(del>0) ;//有可能更新答案 
	if(del<0) ;//有可能返回历史版本
	for(int i=g[u];i;i=e[i].nxt)
		if(e[i].to!=fa[u]&&!big[e[i].to])
			add(e[i].to,del);
} 
inline void dsu(int u,bool kep){
	for(int i=g[u];i;i=e[i].nxt)
		if(e[i].to!=fa[u]&&e[i].to!=son[u])
			dsu(e[i].to,false);
	if(son[u]){
		dsu(son[u],true);big[son[u]]=true;
	}
	add(u,1);
	ans[u]=/*当前答案*/;
	if(son[u]) big[son[u]]=false;
	if(!kep){
		add(u,-1);//清除数据,返回历史版本
	}
}

计算几何

struct point{
    int x,y;
};
point operator - (point a,point b){
    return (point){a.x-b.x,a.y-b.y};
}
ll operator * (point a,point b){
    return 1ll*a.x*b.y-1ll*b.x*a.y;
}

凸包

时间复杂度:\(O(nlogn)\).

#define N 100005
#define eps 1e-13
bool operator < (point a,point b){
    if(a.x!=b.x) return a.xdis(y,a[1]); 
    return x.an1&&(a[i]-a[m-1])*(a[m]-a[m-1])>0) --m;
        a[++m]=a[i];
    }
    n=m;
} 

旋转卡壳

时间复杂度:\(O(n)\).

#define N 100005
point a[N];int n;
inline double sqr(int k){
    return (double)(k*k);
}
inline double dis(point x){
    return sqrt(sqr(x.x)+sqr(x.y));
}
inline int Nxt(int k){
    return (++k>n)?1:k;
}
inline double rotate(){
    point p;double di,dia=0.0;
    if(n==1) return dia;
    for(int i=1,j=2;i<=n;++i){
        p=a[Nxt(i)]-a[i];
        while(abs(p*(a[j]-a[i]))

转角法

时间复杂度:\(O(n)\).

point a[N];int n;
inline int cmp(ll x){
    return x?(x>0?1:-1):0;
}
inline bool onseg(point p,point a,point b){
    if(cmp((a-p)*(b-p))) return false;
    return cmp(a.x-p.x)*cmp(b.x-p.x)<=0&&cmp(a.y-p.y)*cmp(b.y-p.y)<=0;
}
inline int chk(point p){
    int cnt=0,d1,d2,k;
    for(int i=1;i<=n;++i){
        if(onseg(p,a[i],a[i+1]) return -1;
        k=cmp((a[i+1]-a[i])*(p-a[i]));
        d1=cmp(a[i].y-p.y);d2=cmp(a[i+1].y-p.y);
        if(k>0&&d1<=0&&d2>0) ++cnt;
        if(k<0&&d2<=0&&d1>0) --cnt;
    }
    return cnt?1:0;
}

平面最近点对

时间复杂度:\(O(nlogn)\).

point a[N];int n;
bool cmpx(point a,point b){
    if(a.x!=b.x) return a.x>1;
    ret=min(md(l,mid),md(mid+1,r));
    while(a[l].x+reta[mid].x) --r;
    sort(a+l,a+r+1,cmpy);
    for(int i=l;i<=r;++i)
        for(int j=min(i+6,r);j>i;--j)
            ret=min(ret,dis(a[i],a[j]));
    sort(a+l,a+r+1,cmpx);
    return ret;
}
inline double middis(){
    sort(a+1,a+1+n,cmpx);
    return md(1,n);
}

半平面交

\(f(x)=Ax+By+C.\\Ax+By+C\geq{0}:(-1,f(-1))->(1,f(1));\\Ax+By+C\leq{0}:(1,f(1))->(-1,f(-1)).\)

struct line{
    point s,t;double an;
}a[N],q[N];
int h,t,n;
inline bool cmp(line a,line b){
    if(fabs(a.an-b.an)>eps) return a.an0;
}
inline point inter(line a,line b){
    double s1,s2,tmp;point ret;
    s1=(b.t-a.s)*(a.t-a.s);
    s2(a.t-a.s)*(b.s-a.s);
    tmp=s2/(s1+s2);
    ret.x=b.s.x+(b.t.x-b.s.x)*tmp;
    ret.y=b.s.y+(b.t.y-b.s.y)*tmp;
    return ret;
}
inline bool chk(point p,line l){
    return (p-l.s)*(l.t-l.s)>0;
}
inline void hpi(){
    int m=1;
    for(int i=1;i<=n;++i)
        a[i].an=atan2(a[i].t.y-a[i].s.y,a[i].t.x-a[i].s.x);
    sort(a+1,a+1+n,cmp);
    for(int i=2;i<=n;++i)
        if(fabs(a[i].an-a[i-1].an)>eps) a[++m]=a[i];
    h=1;t=0;
    for(int i=1;i<=m;++i){
        while(h=3;
}

数论

FFT

时间复杂度:\(O(nlogn)\).

#define N 100005
typedef long long ld;
const ld pi=acos(-1.0);
struct cp{
	ld x,y;
	cp() {}
	cp(ld x,ld y):x(x),y(y) {}
	friend cp operator + (cp a,cp b){
		return cp(a.x+b.x,a.y+b.y); 
	}
	friend cp operator - (cp a,cp b){
		return cp(a.x-b.x,a.y-b.y);
	}
	friend cp operator * (cp a,cp b){
		return cp(a.x*b.x-a.y*b.y,a.y*b.x+a.x*b.y);
	}
}a[N],b[N],c[N];
namespace FFT{
	const int F=1e5+10;
	cp w[2][F];int re[F],n;
	inline void init(int k){
		k<<=1;n=1;while(n>1;
			for(cp *p=a;p!=a+n;p+=l){
				for(int i=0;i

高斯消元

时间复杂度:\(O(n^3)\).

#define N 101
#define eps 1e-13
double a[N][N],ans[N];
int n;bool b[N];
inline void gauss(int n){
	int m=0;double tmp;
	memset(b,0,sizeof(b));
	for(int i=0;ieps){
				for(int k=i;k<=n;++k)
					swap(a[m][k],a[j][k]);
				break; 
			}
		}
		if(fabs(a[m][i])eps){
				tmp=a[j][i]/a[m][i];
				for(int k=i;k<=n;++k)
					a[j][k]-=tmp*a[m][k];
			}
		b[i]=true;++m;
	}
	for(int i=0;ieps){
				ans[i]=a[j][n]/a[j][i];break;
			}
}

字符串

SA

时间复杂度:\(O(nlogn)\).

#define N 100005
int a[N],sa[N],rk[N],ht[N],fir[N],sec[N],bu1[N],bu2[N],tmp[N],n;
inline void getSA(){
	memset(bu1,0,sizeof(bu1));
	for(int i=1;i<=n;++i) ++bu1[a[i]];
	for(int i=1;i<=n;++i) bu1[i]+=bu1[i-1];
	for(int i=n;i;--i) sa[bu1[a[i]]--]=i;
	rk[sa[1]]=1;
	for(int i=2;i<=n;++i){
		rk[sa[i]]=rk[sa[i-1]];
		if(a[sa[i]]!=a[sa[i-1]]) ++rk[sa[i]];
	}
	for(int t=1;rk[sa[n]]n)?0:rk[i+t])];
		}
		for(int i=1;i<=n;++i) bu2[i]+=bu2[i-1];
		for(int i=n;i;--i) tmp[bu2[sec[i]]--]=i;
		for(int i=1;i<=n;++i) bu1[i]+=bu1[i-1];
		for(int i=n;i;--i) sa[bu1[fir[tmp[i]]]--]=tmp[i];
		rk[sa[1]]=1;
		for(int i=2;i<=n;++i){
			rk[sa[i]]=rk[sa[i-1]];
			if(fir[sa[i]]!=fir[sa[i-1]]||sec[sa[i]]!=sec[sa[i-1]]) ++rk[sa[i]];
		}
	}
	for(int i=1,j,k=0;i<=n;++i){
		if(k) --k;
		j=sa[rk[i]-1];
		while(j+k<=n&&i+k<=n&&a[j+k]==a[i+k]) ++k;
		ht[rk[i]]=k;
	}
}

2017-04-21 11:38:49