[模板]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<int> 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.x<b.x;
return a.y<b.y;
}
inline double sqr(int k){
return (double)(k*k);
}
inline double dis(point x,point y){
return sqr(x.x-y.x)+sqr(x.y-y.y);
}
inline bool cmp(point x,point y){
if(fabs(x.an-y.an)<eps)
return dis(x,a[1])>dis(y,a[1]);
return x.an<y.an;
}
inline void convex(point a[],int &n){
for(int i=2;i<=n;++i)
if(a[i]<a[1]) swap(a[i],a[1]);
for(int i=2;i<=n;++i)
a[i].an=atan2(a[i].y-a[1].y,a[i].x-a[1].x);
sort(a+2,a+1+n,cmp);
int m=1;a[++n]=a[1];
for(int i=2;i<=n;++i){
if(fabs(a[i].an-a[i-1].an)<eps) continue;
while(m>1&&(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]))<abs(p*(a[Nxt(j)]-a[i]))) j=Nxt(j);
dia=max(dia,max(dis(a[i]-a[j]),dis(a[Nxt(i)]-a[Nxt(j)])));
}
return dia;
}
转角法
时间复杂度:\(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<b.x;
return a.y<b.y;
}
bool cmpy(point a,point b){
if(a.y!=b.y) return a.y<b.y;
return a.x<b.x;
}
inline double sqr(int k){
return (double)(k*k);
}
inline double dis(point a,point b){
return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
inline double md(int l,int r){
double ret=INF;
if(r-l<=20){
for(int i=l;i<r;++i)
for(int j=i+1;j<=r;++j)
ret=min(ret,dis(a[i],a[j]));
return ret;
}
int mid=(l+r)>>1;
ret=min(md(l,mid),md(mid+1,r));
while(a[l].x+ret<a[mid].x) ++l;
while(a[r].x-ret>a[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.an<y.an;
return (a.t-a.s)*(b.s-a.s)>0;
}
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<t&&chk(inter(q[t],q[t-1]),a[i]) --t;
while(h<t&&chk(inter(q[h],q[h+1]),a[i]) ++h;
q[++t]=a[i];
}
while(h<t&&chk(inter(q[t],q[t-1]),q[h]) --t;
while(h<t&&chk(inter(q[h],q[h+1]),q[t]) ++h;
return t-h+1>=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<k) n<<=1;
for(int i=0;i<n;++i){
w[0][i]=cp(cos(pi*2/n*i),sin(pi*2/n*i));
w[1][i]=cp(w[0][i].x,-w[0][i].y);
}
k=0;while((1<<k)<n) ++k;
for(int i=0,t;i<n;++i){
t=0;
for(int j=0;j<k;++j)
if(i&(1<<j)) t|=(1<<k-j-1);
re[i]=t;
}
}
inline void DFT(cp *a,int ty){
cp *o=w[ty];
for(int i=0;i<n;++i)
if(i<re[i]) swap(a[i],a[re[i]]);
cp tmp;
for(int l=2,m;l<=n;l<<=1){
m=l>>1;
for(cp *p=a;p!=a+n;p+=l){
for(int i=0;i<m;++i){
tmp=o[n/l*i]*p[i+m];
p[i+m]=p[i]-tmp;p[i]=p[i]+tmp;
}
}
}
if(ty) for(int i=0;i<n;++i)
a[i].x/=(ld)(n),a[i].y/=(ld)(n);
}
}
inline void Aireen(){
FFT::DFT(a,0);FFT::DFT(b,0);
for(int i=0;i<FFT::n;++i)
c[i]=a[i]*b[i];
FFT::DFT(c,1);
}
高斯消元
时间复杂度:\(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;i<n;++i){
for(int j=m;j<n;++j){
if(fabs(a[j][i])>eps){
for(int k=i;k<=n;++k)
swap(a[m][k],a[j][k]);
break;
}
}
if(fabs(a[m][i])<eps) continue;
for(int j=0;j<n;++j)
if(j!=m&&fabs(a[j][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;i<n;++i)
if(b[i]) for(int j=0;j<n;++j)
if(fabs(a[j][i])>eps){
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;t<<=1){
memset(bu1,0,sizeof(bu1));
memset(bu2,0,sizeof(bu2));
for(int i=1;i<=n;++i){
++bu1[fir[i]=rk[i]];
++bu2[sec[i]=((i+t>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