[OI]省选前模板整理
省选前把板子整理一遍,如果发现有脑抽写错的情况,欢迎各位神犇打脸 :)
数学知识
数论:
//组合数
//C(n,m) 在n个数中选m个的方案数
ll C[N][N];
void get_C(int n)
{
for(int i=1;i<=n;i++)
{
C[i][i]=C[i][0]=1;
for(int j=1;j<i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
}
//欧几里得算法
//(a,b)
ll gcd(ll a,ll b)
{
return b==0? a:gcd(b,a%b);
}
//拓展欧几里得算法
//解同余方程 a*x+b*y = (a,b)
ll exgcd(ll a,ll b,ll& d,ll& x,ll& y)
{
if(!b) { d=a; x=1; y=0; }
else { exgcd(b,a%b,d,y,x); y-=x*(a/b); }
}
//逆元
//a*inv(a,n) = 1 mod n
ll inv(ll a,ll n)
{
ll d,x,y;
exgcd(a,n,d,x,y);
return d==1? (x+n)%n:-1;
}
//lucas定理
//计算较大,有模数的组合数
ll fac[N];
void get_pre(int n)
{
for(int i=1;i<=n;i++)
fac[i]=(fac[i-1]*i)%mod;
}
ll C(ll n,ll m,ll mod)
{
if(n<m) return 0;
if(n<mod&&m<mod)
return fac[n]*inv(fac[m],mod)%mod*inv(fac[n-m],mod)%mod;
return C(n/mod,m/mod,mod)*C(n%mod,m%mod,mod)%mod;
}
//快速幂
//a^p % mod
ll pow(ll a,ll p,ll mod)
{
ll ans=1;
while(p)
{
if(p&1) ans=(ans*a)%mod;
a=(a*a)%mod; p>>=1;
}
return ans;
}
//中国剩余定理
//解线性同余方程组
//sigma{ ai*(1-ai*mi) } % M , ai*mi+wi*y=1
ll a[N],m[N];
ll china(int n)
{
ll M=1,d,x=0,y;
for(int i=1;i<=n;i++) M*=m[i];
for(int i=1;i<=n;i++)
{
ll w=M/m[i];
exgcd(m[i],w,d,d,y);
x=(x+y*w*a[i])%M;
}
return (x+M)%M;
}
//大步小步算法
//计算a^x=b mod n中的最小x
map<int,int> mp;
int BSGS(int a,int b,int n)
{
int m=sqrt(n)+1,e=1,i;
int v=inv(pow(a,m,n),n);
mp[e]=0;
for(i=1;i<m;i++)
{
e=(e*m)%n;
if(!mp.count(e)) mp[e]=i;
}
for(i=0;i<m;i++)
{
if(mp.count(b)) return i*m+mp[b];
b=(b*v)%mod;
}
return -1;
}
//快速筛法求素数表
int su[N],vis[N];
void get_su(int n)
{
for(int i=2;i<=n;i++)
{
if(!vis[i]) su[++su[0]]=i;
for(int j=1;j<=su[0]&&i*su[j]<=n;j++)
{
vis[i*su[j]]=1;
if(i%su[j]==0) break;
}
}
}
//欧拉函数
//phi(n)小于n的数中与n互素的数的个数
ll get_phi(int n)
{
int m=sqrt(n)+1;
ll ans=n;
for(int i=2;i<=m;i++) if(n%i==0)
{
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
if(n>1) ans=ans/n*(n-1);
return ans;
}
ll phi[N];
void get_phi_table(int n)
{
phi[1]=1;
for(int i=2;i<=n;i++) if(!phi[i])
{
for(int j=i;j<=n;j+=i)
{
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
//莫比乌斯函数
int mu[N],su[N],vis[N];
void get_mu(int n)
{
mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i]) mu[i]=-1,su[++su[0]]=i;
for(int j=1;j<=su[0]&&i*su[j]<=n;j++)
{
vis[i*su[j]]=1;
if(i%su[j]==0) mu[i*su[j]]=0;
else mu[i*su[j]]=-mu[i];
}
}
}
//高斯消元
//解线性方程组
double a[N][N];
void gause(int n)
{
for(int i=1;i<=n;i++)
{
int r=i;
for(int j=i+1;j<=n;j++)
if(fabs(a[j][i])>fabs(a[r][i])) r=i;
for(int j=1;j<=n+1;j++) swap(a[i][j],a[r][j]);
for(int j=n+1;j>=i;j--)
for(int k=i+1;k<=n;k++)
a[k][j]-=a[k][i]/a[i][i]*a[i][j];
}
for(int i=n;i;i--)
{
for(int j=i+1;j<=n;j++)
a[i][n+1]-=a[j][n+1]*a[i][j];
a[i][n+1]/=a[i][i];
}
}
高精度:
int trans(char* s,int st,int ed)
{
int x=0;
for(int i=st;i<ed;i++) x=x*10+s[i]-'0';
return x;
} struct Bign
{
int len; ll N[maxn];
Bign() { len=0; memset(N,0,sizeof(N)); }
Bign(ll num) { *this=num; }
Bign(const char* s) { *this=s; }
void print()
{
printf("%d",N[len-1]);
for(int i=len-2;i>=0;i--)
printf("%08d",N[i]);
puts("");
}
Bign operator = (const ll x)
{
ll num=x;
while(num>base)
{
N[len++]=num%base;
num/=base;
}
if(num) N[len++]=num;
return *this;
}
Bign operator = (char* s)
{
int L=strlen(s);
len=(L-1)/wlen+1;
for(int i=0;i<len;i++)
{
int ed=L-i*wlen;
int st=max(0,ed-wlen);
N[i]=trans(s,st,ed);
}
return *this;
}
bool operator < (const Bign& B) const
{
if(len!=B.len) return len<B.len;
for(int i=len-1;i>=0;i--)
if(N[i]!=B.N[i]) return N[i]<B.N[i];
return 0;
}
bool operator <= (const Bign& B) const
{
return !(B<(*this));
} void clear()
{
while(len>1&&N[len-1]==0) len--;
} Bign operator + (const Bign& B) const
{
Bign C;
C.len=max(len,B.len)+10;
for(int i=0;i<C.len;i++)
{
C.N[i]+=N[i]+B.N[i];
C.N[i+1]+=C.N[i]/base;
C.N[i]%=base;
}
C.clear();
return C;
}
Bign operator - (Bign B)
{
Bign C=*this;
C.len=max(C.len,B.len);
for(int i=0;i<C.len;i++)
{
if(C.N[i]<B.N[i]) C.N[i+1]--,C.N[i]+=base;
C.N[i]=C.N[i]-B.N[i];
}
C.clear();
return C;
}
Bign operator * (const Bign& B) const
{
Bign C;
C.len=len+B.len;
for(int i=0;i<len;i++)
for(int j=0;j<B.len;j++)
C.N[i+j]+=N[i]*B.N[j];
for(int i=0;i<C.len;i++)
{
C.N[i+1]+=C.N[i]/base;
C.N[i]%=base;
}
C.clear();
return C;
}
Bign operator / (const Bign& B)
{
Bign C,F;
C.len=len;
for(int i=len-1;i>=0;i--)
{
F=F*base;
F.N[0]=N[i];
while(B<=F)
{
F=F-B;
C.N[i]++;
}
}
C.clear();
return C;
}
Bign operator % (const Bign& B)
{
Bign r=*this/B;
return *this-r*B;
} }A,B;
矩阵乘法:
//矩阵乘法
struct Mat
{
int r,c; ll N[maxn][maxn];
Mat(int r=0,int c=0)
{
this->r=r,this->c=c;
memset(N,0,sizeof(N));
}
Mat operator * (const Mat& B) const
{
Mat C(r,B.c);
for(int i=0;i<r;i++)
for(int j=0;j<B.c;j++)
for(int k=0;k<c;k++)
C.N[i][j]=(C.N[i][j]+N[i][k]*B.N[k][j])%mod;
return C;
}
Mat operator ^ (int p)
{
Mat ans(r,r),tmp=*this;
for(int i=0;i<r;i++) ans.N[i][i]=1;
while(p)
{
if(p&1) ans=ans*tmp;
tmp=tmp*tmp; p>>=1;
}
return ans;
} };
数据结构
树状数组:
//树状数组
int C[N],mx;
void Add(int x,int v)
{
for(int i=x;i<=mx;i+=i&-i) C[i]+=v;
}
int query(int x)
{
int ans=0;
for(int i=x;i;i-=i&-i) ans+=C[i];
return ans;
}
线段树:
//线段树
//区间加,区间乘,区间求和
int mod;
struct Tnode
{
int u,l,r;
ll sum,add,mul;
void mulv(ll x) {
sum=(sum*x)%mod;
mul=(mul*x)%mod;
add=(add*x)%mod;
}
void addv(ll x) {
sum=(sum+(r-l+1)*x%mod)%mod;
add=(add+x)%mod;
}
void pushdown() ;
void maintain() ;
}T[N];
void Tnode::pushdown() {
if(mul^1) {
T[u<<1].mulv(mul);
T[u<<1|1].mulv(mul);
mul=1;
}
if(add) {
T[u<<1].addv(add);
T[u<<1|1].addv(add);
add=0;
}
}
void Tnode::maintain() {
sum=(T[u<<1].sum+T[u<<1|1].sum)%mod;
} void update(int u,int L,int R,int x,int f)
{
T[u].pushdown();
if(L<=T[u].l&&T[u].r<=R) {
if(!f) T[u].addv(x);
else T[u].mulv(x);
} else {
int mid=T[u].l+T[u].r>>1;
if(L<=mid) update(u<<1,L,R,x,f);
if(mid<R) update(u<<1|1,L,R,x,f);
T[u].maintain();
}
}
ll query(int u,int L,int R)
{
T[u].pushdown();
if(L<=T[u].l&&T[u].r<=R)
return T[u].sum;
else {
int mid=T[u].l+T[u].r>>1;
ll ans=0;
if(L<=mid) ans=(ans+query(u<<1,L,R))%mod;
if(mid<R) ans=(ans+query(u<<1|1,L,R))%mod;
return ans;
}
}
ll a[N]; void build(int u,int l,int r)
{
T[u]=(Tnode){ u,l,r,0,0,1 };
if(l==r) {
T[u].sum=a[l];
} else {
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
T[u].maintain();
}
}
Treap:
//Treap
struct Node
{
Node *ch[2];
int v,r,m,w,s;
Node(int v):v(v) { ch[0]=ch[1]=NULL; r=rand(); s=w=1; }
int cmp(int x) {
if(v==x) return -1;
return x<v? 0:1;
}
void maintain() {
s=w;
if(ch[0]!=NULL) s+=ch[0]->s;
if(ch[1]!=NULL) s+=ch[1]->s;
}
}; void rotate(Node* &o,int d)
{
Node* k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
o->maintain(); k->maintain(); o=k;
}
void insert(Node *&o,int x)
{
if(o==NULL) o=new Node(x);
int d=o->cmp(x);
if(d==-1) o->w++;
else {
insert(o->ch[d],x);
if(o->ch[d]->r > o->r) rotate(o,d^1);
}
o->maintain();
}
void remove(Node *&o,int x)
{
int d=o->cmp(x);
if(d==-1)
{
if(o->s>1) { o->w--; o->maintain(); return ; }
else {
if(o->ch[0]!=NULL&&o->ch[1]!=NULL) {
int d2=o->ch[0]->r > o->ch[1]->r ? 1:0;
rotate(o,d2); remove(o->ch[d2],x);
} else {
if(o->ch[0]!=NULL) o=o->ch[0]; else o=o->ch[1];
delete o;
}
}
} else
remove(o->ch[d],x);
if(o!=NULL) o->maintain();
}
int kth(Node* o,int rk)
{
if(o==NULL) return 0;
int s=o->ch[0]==NULL? 0:o->ch[0]->s;
if(rk==s+1) return o->v;
else if(rk<=s) return kth(o->ch[0],rk);
else return kth(o->ch[1],rk-s-o->w);
}
int rank(Node* o,int x)
{
if(o==NULL) return 0;
int s=o->ch[0]==NULL? 0:o->ch[0]->s;
int d=o->cmp(x);
if(d==-1) return 1;
else if(d==0) return rank(o->ch[0],x);
else return s+o->w+rank(o->ch[1],x);
}
int tmp;
void before(Node* o,int x)
{
if(o==NULL) return ;
if(o->v<x) { tmp=max(tmp,o->v); before(o->ch[1],x); }
else before(o->ch[0],x);
}
void after(Node* o,int x)
{
if(o==NULL) return ;
if(o->v>x) { tmp=min(tmp,o->v); after(o->ch[0],x); }
else after(o->ch[1],x);
}
splay:
//splay自上而下
struct Node
{
Node *ch[2];
int s;
int cmp(int x)
{
int d=x-ch[0]->s;
if(d==1) return -1;
return d<=0? 0:1;
}
void maintain()
{
s=ch[0]->s+ch[1]->s;
}
void pushdown() {}
}mempool[N],*G=mempool; Node* null=new Node();
void rotate(Node* &o,int d)
{
Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d],k->ch[d]=o;
o->maintain(); k->maintain(); o=k;
}
void splay(Node* &o,int k)
{
o->pushdown();
int d=o->cmp(k);
if(d==1) k-=o->ch[0]->s+1;
if(d!=-1) {
Node* p=o->ch[d];
p->pushdown();
int d2=p->cmp(k),k2=d2==0? k:k-p->ch[d]->s-1;
if(d2!=-1) {
splay(p->ch[d2],k2);
if(d==d2) rotate(o,d^1); else rotate(o->ch[d],d);
}
rotate(o,d^1);
}
}
Node* merge(Node* left,Node* right)
{
splay(left,left->s);
left->ch[1]=right,left->maintain();
return left;
}
void split(Node* o,int k,Node*&left,Node*&right)
{
splay(o,k);
left=o,right=left->ch[1],left->ch[1]=NULL;
left->maintain();
}
Node* build(int l,int r)
{
if(r<l) return null;
int mid=l+r>>1;
G->s=1;
G->ch[0]=build(l,mid-1);
G->ch[1]=build(mid+1,r);
G->maintain();
return G++;
}
主席树:
//主席树
struct Tnode
{
Tnode *ls,*rs;
int sum;
} *T[N*50],mempool[N*50],*G=mempool; Tnode* Nw(Tnode* l,Tnode* r,int x)
{
G->ls=l,G->rs=r,G->sum=x;
return G++;
}
Tnode* build(Tnode* p,int l,int r,int pos)
{
if(l==r)
return Nw(T[0],T[0],p->sum+1);
else {
int mid=l+r>>1;
if(pos<=mid) return Nw(build(p->ls,l,mid,pos),p->rs,p->sum+1);
else return Nw(p->ls,build(p->rs,mid+1,r,pos),p->sum+1);
}
}
int query(Tnode* x,int l,int r,int pos)
{
if(l==r) return x->sum;
else {
int mid=l+r>>1;
if(pos<=mid) return query(x->ls,l,mid,pos);
else return query(x->rs,mid+1,r,pos);
}
}
Link-Cut-Tree
//Link-Cut-Tree
namespace LCT
{ struct Node {
Node *ch[2],*fa;
int rev;
//others v
Node() {};
Node(int x) ;
void reverse() {
swap(ch[0],ch[1]);
rev^=1;
}
void up_push() {
if(fa->ch[0]==this||fa->ch[1]==this)
fa->up_push();
if(rev) {
ch[0]->reverse();
ch[1]->reverse();
rev=0;
}
}
void maintain() { }
} T[N<<1],*null=&T[0];
Node::Node(int x) {
ch[0]=ch[1]=fa=null;
rev=0; //v=x;
}
void rot(Node* o,int d) {
Node* p=o->fa;
p->ch[d]=o->ch[d^1];
o->ch[d^1]->fa=p;
o->ch[d^1]=p;
o->fa=p->fa;
if(p==p->fa->ch[0])
p->fa->ch[0]=o;
else if(p==p->fa->ch[1])
p->fa->ch[1]=o;
p->fa=o;
p->maintain();
}
void splay(Node* o) {
o->up_push();
Node *nf,*nff;
while(o->fa->ch[0]==o||o->fa->ch[1]==o) {
nf=o->fa,nff=nf->fa;
if(o==nf->ch[0]) {
if(nf==nff->ch[0]) rot(nf,0);
rot(o,0);
} else {
if(nf==nff->ch[1]) rot(nf,1);
rot(o,1);
}
}
o->maintain();
}
void Access(Node* o) {
Node *son=null;
while(o!=null) {
splay(o);
o->ch[1]=son;
o->maintain();
son=o; o=o->fa;
}
}
void evert(Node* o) {
Access(o);
splay(o);
o->reverse();
}
void Link(Node* u,Node* v) {
evert(u);
u->fa=v;
}
void Cut(Node* u,Node* v) {
evert(u);
Access(v),splay(v);
v->ch[0]=u->fa=null;
v->maintain();
}
Node* find(Node* o) {
while(o->fa!=null) o=o->fa;
return o;
} }
using namespace LCT ;
图
2-SAT:
//2-sat
struct TwoSAT {
int n;
vector<int> g[N<<1];
int st[N<<1],mark[N<<1],top; bool dfs(int x) {
if(mark[x^1]) return 0;
if(mark[x]) return 1;
mark[x]=1;
st[++top]=x;
for(int i=0;i<g[x].size();i++)
if(!dfs(g[x][i])) return 0;
return 1;
}
void init(int n) {
this->n=n;
for(int i=0;i<2*n;i++) g[i].clear();
memset(mark,0,sizeof(mark));
}
void addc(int x,int xval,int y,int yval) {
x=x*2+xval;
y=y*2+yval;
g[x^1].push_back(y);
g[y^1].push_back(x);
}
bool solve() {
for(int i=0;i<2*n;i+=2) {
if(!mark[i]&&!mark[i+1]) {
top=0;
if(!dfs(i)) {
while(top) mark[st[top--]]=0;
if(!dfs(i+1)) return 0;
}
}
}
return 1;
} } s;
有向图的强联通分量:
//tarjan求SCC
struct Edge {
int v,nxt;
}e[M];
int en=1,front[N];
void adde(int u,int v)
{
e[++en]=(Edge){v,front[u]}; front[u]=en;
} int n,top,dfn;
int st[N],sccno[N],scc_cnt,pre[N],lowlink[N]; void tarjan(int u)
{
pre[u]=lowlink[u]=++dfn;
st[++top]=u;
trav(u,i) {
int v=e[i].v;
if(!pre[v]) {
tarjan(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
} else
if(!sccno[v])
lowlink[u]=min(lowlink[u],pre[v]);
}
if(lowlink[u]==pre[u]) {
scc_cnt++;
for(;;) {
int x=st[top--];
sccno[x]=scc_cnt;
if(x==u) break;
}
}
}
无向图的边的双连通分量:
//BCC
struct Edge {
int u,v,nxt;
}e[M];
int en=1,front[N];
void adde(int u,int v)
{
e[++en]=(Edge){u,v,front[u]}; front[u]=en;
} Edge st[N];
vector<int> bcc[N];
int pre[N],iscut[N],bccno[N],top,dfn,bcc_cnt; int dfs(int u,int fa)
{
int lowu=pre[u]=++dfn;
int child=0;
trav(u,i) {
int v=e[i].v;
Edge E=e[i];
if(!pre[v]) {
st[++top]=E;
child++;
int lowv=dfs(v,u);
lowu=min(lowu,lowv);
if(lowv>=pre[u]) {
iscut[u]=1;
bcc_cnt++;
for(;;) {
Edge x=st[top--];
if(bccno[x.u]!=bcc_cnt) {
bccno[x.u]=bcc_cnt;
bcc[bcc_cnt].push_back(x.u);
}
if(bccno[x.v]!=bcc_cnt) {
bccno[x.v]=bcc_cnt;
bcc[bcc_cnt].push_back(x.v);
}
if(x.u==u&&x.v==v) break;
}
}
} else
if(pre[v]<pre[u] && v!=fa) {
st[++top]=E;
lowu=min(lowu,pre[v]);
}
}
if(fa<0&&child==1) iscut[u]=0;
return lowu;
}
最短路:
//spfa struct Edge {
int v,w,nxt;
}e[M];
int en=1,front[N];
void adde(int u,int v,int w)
{
e[++en]=(Edge){v,w,front[u]}; front[u]=en;
} queue<int> q;
int inq[N],dis[N];
void spfa(int s)
{
dis[s]=0; inq[s]=1;
q.push(s);
while(!q.empty()) {
int u=q.front(); q.pop();
inq[u]=0;
trav(u,i) {
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w) {
dis[v]=dis[u]+e[i].w;
if(!inq[v]) {
inq[v]=1;
q.push(v);
}
}
}
}
} //dijkstra struct Node {
int id,dis;
bool operator < (const Node& rhs) const
{
return dis>rhs.dis;
}
}; priority_queue<Node> q;
int n,m,s;
int vis[N],dis[N]; void dijkstra(int s)
{
FOR(i,1,n) dis[i]=inf;
dis[s]=0; q.push((Node){s,0});
while(!q.empty()) {
int u=q.top().id;
q.pop();
if(vis[u]) continue;
vis[u]=1;
trav(u,i) {
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w) {
dis[v]=dis[u]+e[i].w;
q.push((Node){v,dis[v]});
}
}
}
}
最小生成树:
//Kruskal int fa[N];
int find(int u)
{
if(!fa[u] || u==fa[u]) return fa[u]=u;
return fa[u]=find(fa[u]);
} struct Edge {
int u,v,w;
bool operator < (const Edge& rhs) const
{
return w<rhs.w;
}
}e[M];
int tot; void Kruskal()
{
sort(e+1,e+tot+1);
for(int i=1;i<=tot;i++) {
int u=e[i].u,v=e[i].v;
int x=find(u),y=find(v);
if(x!=y) {
fa[x]=y;
//加入树边(u,v)
}
}
}
最大流:
//Dinic算法求最大流
struct Edge {
int u,v,cap,flow;
};
struct Dinic {
int d[N],cur[N],vis[N];
vector<Edge> es;
vector<int> g[N];
queue<int> q; void AddEdge (int u,int v,int w) {
es.push_back((Edge){u,v,w,0});
es.push_back((Edge){v,u,0,0});
int m=es.size();
g[u].push_back(m-2);
g[v].push_back(m-1);
}
bool bfs(int s,int t) {
memset(vis,0,sizeof(vis));
d[s]=0; vis[s]=1;
q.push(s);
while(!q.empty()) {
int u=q.front(); q.pop();
FOR(i,0,(int)g[u].size()-1) {
Edge& e=es[g[u][i]];
int v=e.v;
if(e.cap>e.flow&&!vis[v]) {
vis[v]=1;
d[v]=d[u]+1;
q.push(v);
}
}
}
return vis[t];
}
int dfs(int u,int a,int t) {
if(u==t||a==0) return a;
int flow=0,f;
for(int& i=cur[u];i<g[u].size();i++) {
Edge& e=es[g[u][i]];
int v=e.v;
if(d[v]==d[u]+1&&(f=dfs(v,min(a,e.cap-e.flow),t))>0) {
e.flow+=f;
es[g[u][i]^1].flow-=f;
flow+=f,a-=f;
if(!a) break;
}
}
return flow;
}
int maxflow(int s,int t) {
int flow=0;
while(bfs(s,t)) {
memset(cur,0,sizeof(cur));
flow+=dfs(s,inf,t);
}
return flow;
}
} dc;
最小费用最大流:
/最短路算法求最小费用最大流
struct Edge {
int u,v,cap,flow,cost;
Edge(int _,int __,int ___,int ____,int _____)
{ u=_,v=__,cap=___,flow=____,cost=_____; }
}; struct MCMF {
int n,m,s,t;
int d[N],p[N],a[N],inq[N];
vector<Edge> es;
vector<int> g[N];
queue<int> q;
void init(int n) {
this->n=n;
es.clear();
for(int i=0;i<=n;i++) g[i].clear();
}
void AddEdge(int u,int v,int w,int c) {
es.push_back(Edge(u,v,w,0,c));
es.push_back(Edge(v,u,0,0,-c));
int m=es.size();
g[u].push_back(m-2);
g[v].push_back(m-1);
}
bool spfa(int s,int t,ll& flow,ll& cost) {
memset(inq,0,sizeof(inq));
for(int i=0;i<=n;i++) d[i]=inf;
inq[s]=1; d[s]=p[s]=0; a[s]=inf;
q.push(s);
while(!q.empty()) {
int u=q.front(); q.pop();
inq[u]=0;
for(int i=0;i<g[u].size();i++) {
Edge& e=es[g[u][i]];
int v=e.v;
if(d[v]>d[u]+e.cost && e.cap>e.flow) {
d[v]=d[u]+e.cost;
a[v]=min(a[u],e.cap-e.flow);
p[v]=g[u][i];
if(!inq[v])
inq[v]=1 , q.push(v);
}
}
}
if(d[t]==inf) return 0;
flow+=a[t],cost+=a[t]*d[t];
for(int x=t;x!=s;x=es[p[x]].u) {
es[p[x]].flow+=a[t];
es[p[x]^1].flow-=a[t];
}
return 1;
}
void mcmf(int s,int t,ll& cost,ll& flow) {
flow=cost=0;
while(spfa(s,t,cost,flow)) ;
}
} mc;
KM算法:
//KM算法求二分图的最佳完美匹配
struct KM {
int slack[N],res[N];
int l[N],r[N],lx[N],rx[N],g[N][N]; void clear(int n) {
for(int i=1;i<=n;i++) {
res[i]=0;
for(int j=1;j<=n;j++) g[i][j]=-1;
}
}
bool find(int x,int n) {
lx[x]=1;
for(int i=1;i<=n;i++)
if(!rx[i]&&g[x][i]!=-1) {
int tmp=g[x][i]-l[x]-r[i];
if(!tmp) {
rx[i]=1;
if(!res[i]||find(res[i],n)) {
res[i]=x;
return 1;
}
} else
slack[i]=min(slack[i],tmp);
}
return 0;
}
int solve(int n) {
if(!n) return 0;
for(int i=1;i<=n;i++) r[i]=0;
for(int i=1;i<=n;i++) {
l[i]=INF;
for(int j=1;j<=n;j++) if(g[i][j]!=-1)
l[i]=min(l[i],g[i][j]);
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) slack[j]=INF;
for(;;) {
for(int j=1;j<=n;j++) lx[j]=rx[j]=0;
if(find(i,n)) break;
int mini=INF;
for(int i=1;i<=n;i++) if(!rx[i])
mini=min(mini,slack[i]);
for(int i=1;i<=n;i++) {
if(lx[i]) l[i]+=mini;
if(rx[i]) r[i]-=mini;
else slack[i]-=mini;
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
ans+=l[i]+r[i];
return ans;
}
} km;
树
LCA:
//倍增法求LCA
//倍增法可以在线构造 比较灵活
struct Edge {
int v,nxt;
}e[M];
int en=1,front[N];
void adde(int u,int v)
{
e[++en]=(Edge){v,front[u]}; front[u]=en;
} int fa[N][D],dep[N]; void dfs(int u)
{
for(int i=1;i<D;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
trav(u,i) {
int v=e[i].v;
if(v!=fa[u][0]) {
fa[v][0]=u;
dep[v]=dep[u]+1;
dfs(v);
}
}
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int t=dep[u]-dep[v];
for(int i=0;i<D;i++)
if(t&(1<<i)) u=fa[u][i];
if(u==v) return u;
for(int i=D-1;i>=0;i--)
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
} //树链剖分求LCA
//比较快
struct Edge {
int v,nxt;
}e[M];
int en=1,front[N];
void adde(int u,int v)
{
e[++en]=(Edge){v,front[u]}; front[u]=en;
} int fa[N],top[N],siz[N],dep[N],son[N];
void dfs1(int u)
{
siz[u]=1; son[u]=0;
trav(u,i) {
int v=e[i].v;
if(v!=fa[u]) {
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
trav(u,i)
if(e[i].v!=fa[u]&&e[i].v!=son[u])
dfs2(e[i].v,e[i].v);
}
int lca(int u,int v)
{
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]? u:v;
}
树链剖分:
//树链剖分
struct Edge {
int v,nxt;
}e[M];
int en=1,front[N];
void adde(int u,int v)
{
e[++en]=(Edge){v,front[u]}; front[u]=en;
} int fa[N],top[N],siz[N],dep[N],son[N],bl[N],dfn;
void dfs1(int u)
{
siz[u]=1; son[u]=0;
trav(u,i) {
int v=e[i].v;
if(v!=fa[u]) {
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int tp)
{
top[u]=tp; bl[u]=++dfn;
if(son[u]) dfs2(son[u],tp);
trav(u,i)
if(e[i].v!=fa[u]&&e[i].v!=son[u])
dfs2(e[i].v,e[i].v);
}
//以合适的数据结构T维护重链
int ans;
int query(int u,int v)
{
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
ans<-query(T,bl[top[u]],bl[u]);
u=fa[top[u]];
}
if(u==v) return ;
if(dep[u]>dep[v]) swap(u,v);
ans<-query(T,bl[u],bl[v]);
<-ans
}
//类似-查询树上任意两节点的方法
void modify() {}
点分治:
//点分治
struct Edge {
int v,nxt;
}e[M];
int en=1,front[N];
void adde(int u,int v)
{
e[++en]=(Edge){v,front[u]}; front[u]=en;
} int rt,n,size,vis[N],siz[N],f[N],dep[N]; void get_root(int u,int fa)
{
siz[u]=1; f[u]=0;
trav(u,i) {
int v=e[i].v;
if(v!=fa) {
get_root(v,u);
siz[u]+=siz[v];
if(siz[v]>f[u]) f[u]=siz[v];
}
}
f[u]=max(f[u],size-siz[u]);
if(f[u]<f[rt]) rt=u;
}
void solve(int u)
{
vis[u]=1;
//计算经过根u的信息
trav(u,i) if(!vis[e[i].v])
{
//统计当前子树信息
//与前i-1个子树信息结合计算贡献
//将当前子树信息加入前i-1个子树信息
}
trav(u,i) if(!vis[e[i].v]) {
int v=e[i].v;
size=siz[v]; rt=0;
get_root(v,-1);
solve(rt);
}
}
int main()
{
//blabla
size=f[0]=n;
rt=0; get_root(rt,-1);
solve(rt);
}
字符串
KMP:
//KMP算法
int f[N]; char s[N];
void get_fail()
{
int j=0;
int n=strlen(s+1);
for(int i=2;i<=n;i++) {
while(j&&s[j+1]!=s[i]) j=f[j];
if(s[j+1]==s[i]) j++;
f[i]=j;
}
}
AC自动机:
//AC自动机
struct AC_auto {
int sz,ch[N][26],f[N],val[N];
AC_auto() {
sz=1;
memset(ch,0,sizeof(ch));
}
void insert(char* s) {
int u=0;
for(int i=0;s[i];i++) {
int c=s[i]-'a';
if(!ch[u][c]) ch[u][c]=++sz;
u=ch[u][c];
}
val[u]=1;
}
void get_fail() {
queue<int> q;
f[0]=0;
for(int c=0;c<26;c++)
if(ch[0][c]) f[ch[0][c]]=0,q.push(ch[0][c]);
while(!q.empty()) {
int qr=q.front(); q.pop();
for(int c=0;c<26;c++) {
int u=ch[qr][c];
if(!u) continue;
q.push(u);
int v=f[qr];
while(v&&!ch[v][c]) v=f[v];
if(val[ch[v][c]]) val[u]=1;
f[u]=ch[v][c];
}
}
}
};
后缀自动机:
//后缀自动机SAM
struct SAM {
int sz,last,fa[N],ch[N][26],l[N];
SAM() {
sz=0; last=++sz;
memset(l,0,sizeof(l));
memset(fa,0,sizeof(fa));
}
void Add(int c) {
int np=++sz,p=last; last=np;
l[np]=l[p]+1;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(l[q]==l[p]+1) fa[np]=q;
else {
int nq=++sz; l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for(;q==ch[p][c];p=fa[p]) ch[p][c]=nq;
}
}
}
//do some other things } sam;
后缀数组:
//后缀数组
#define rep(a,b,c) for(int a=(b);a>=(c);a--)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
char s[N];
int c[N],t[N],t2[N],height[N],rank[N],sa[N];
void build_sa(int m,int n) {
int *x=t,*y=t2,p,k;
FOR(i,0,m-1) c[i]=0;
FOR(i,0,n-1) c[x[i]=s[i]]++;
FOR(i,0,m-1) c[i]+=c[i-1];
rep(i,n-1,0) sa[--c[x[i]]]=i; for(k=1;k<=n;k<<=1) {
p=0;
FOR(i,n-k,n-1) y[p++]=i;
FOR(i,0,n-1) if(sa[i]>=k) y[p++]=sa[i]-k; FOR(i,0,m-1) c[i]=0;
FOR(i,0,n-1) c[x[y[i]]]++;
FOR(i,0,m-1) c[i]+=c[i-1];
rep(i,n-1,0) sa[--c[x[y[i]]]]=y[i]; swap(x,y);
p=1; x[sa[0]]=0;
FOR(i,1,n-1)
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]? p-1:p++;
if(p>=n) break;
m=p;
}
}
void get_height(int n)
{
FOR(i,0,n-1) rank[sa[i]]=i;
int k=0;
FOR(i,0,n-1) {
if(k) k--;
int j=sa[rank[i]-1];
while(s[i+k]==s[j+k]) k++;
height[rank[i]]=k;
}
}
Manacher:
//Manacher算法
char s[N],a[N];
int p[N];
void Add(int l,int r)
{
l=l/2,r=r/2-1;
if(l>r) return ;
//q[++tot]=(Seg){l,r};
//[l,r]为一个极大回文串
}
void Manacher()
{
int n=strlen(s+1);
int m=n*2+1;
for(int i=1;i<=n;i++) {
a[i<<1]=s[i];
a[i<<1|1]='#';
}
a[0]='+',a[1]='#',a[m+1]='-';
int mx=0,id;
for(int i=1;i<=m;i++) {
if(mx>i) p[i]=min(mx-i,p[id*2-i]);
else p[i]=1;
while(a[i-p[i]]==a[i+p[i]]) p[i]++;
Add(i-p[i],i+p[i]);
if(p[i]+i>mx) mx=i+p[i],id=i;
}
}
计算几何
计算几何基础知识:
//计算几何基础 const double eps = 1e-10;
int dcmp(double x) {
if(fabs(x)<eps) return 0; else return x<0? -1:1;
} struct Pt {
double x,y;
Pt(double x=0,double y=0):x(x),y(y) {}
};
typedef Pt vec; vec operator - (Pt A,Pt B) { return vec(A.x-B.x,A.y-B.y); }
vec operator + (vec A,vec B) { return vec(A.x+B.x,A.y+B.y); }
vec operator * (vec A,double p) { return vec(A.x*p , A.y*p); }
bool operator < (const Pt& a,const Pt& b) {
return a.x<b.x || (a.x==b.x && a.y<b.y);
}
bool operator == (const Pt& a,const Pt& b) {
return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;
} double cross(vec A,vec B) { return A.x*B.y-A.y*B.x; }
double Dot(vec A,vec B) { return A.x*B.x+A.y*B.y; }
double Len(vec A) { return sqrt(Dot(A,A)); }
double Angle(vec A,vec B) { return acos(Dot(A,B)/Len(A)/Len(B)); } //逆时针旋转rad角度
vec rotate(vec A,double rad) {
return vec(A.x*cos(rad)-A.y*sin(rad) , A.x*sin(rad)+A.y*cos(rad));
}
//法向量 左转90度 长度归1
vec Normal(vec A)
{
double L=Len(A);
return vec(-A.y/L,A.x/L);
}
//判断点在线段上
bool OnSeg(Pt P,Pt a1,Pt a2) {
return dcmp(cross(a1-P,a2-P))==0 && dcmp(Dot(a1-P,a2-P))<0;
}
//直线交点
Pt LineIntersection(Pt P,vec v,Pt Q,vec w) {
vec u=P-Q;
double t=cross(w,u)/cross(v,w);
return P+v*t;
}
double DistoLine(Pt P,Pt A,Pt B) {
vec v1=B-A,v2=P-A;
return fabs(cross(v1,v2))/Len(v1);
}
//线段不含端点 判断相交
bool SegIntersection(Pt a1,Pt a2,Pt b1,Pt b2) {
double c1=cross(a2-a1,b1-a1) , c2=cross(a2-a1,b2-a1) ,
c3=cross(b2-b1,a1-b1) , c4=cross(b2-b1,a2-b1);
return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
// b1 b2在线段a1a2的两侧 a1 a2在线段b1b2的两侧 规范相交
}
//线段含端点 判断线段严格相交
bool SegInter(Pt s1, Pt e1, Pt s2, Pt e2) {
if( min(s1.x, e1.x) <= max(s2.x, e2.x) &&
min(s1.y, e1.y) <= max(s2.y, e2.y) &&
min(s2.x, e2.x) <= max(s1.x, e1.x) &&
min(s2.y, e2.y) <= max(s1.y, e1.y) &&
cross(e1-s1,s2-s1) * cross(e1-s1,e2-s1) <= 0 &&
cross(e2-s2,s1-s2) * cross(e2-s2,e1-s2) <= 0
) return true;
return false;
}
//点到线段的距离
double DistoSeg(Pt P,Pt A,Pt B) {
if(A==B) return Len(P-A);
vec v1=B-A , v2=P-A , v3=P-B;
if(dcmp(Dot(v1,v2))<0) return Len(v2);
else if(dcmp(Dot(v1,v3))>0) return Len(v3);
else return fabs(cross(v1,v2))/Len(v1);
}
//多边形面积
double PolygonArea(Pt* p,int n)
{
double S=0;
for(int i=1;i<n-1;i++)
S+=cross(p[i]-p[0],p[i+1]-p[0]);
return S/2;
}
凸包:
//凸包
const int N = 400000+10;
const double PI = acos(-1.0);
const double eps = 1e-12; int dcmp(double x) {
if(fabs(x)<eps) return 0; else return x<0? -1:1;
} struct Pt {
double x,y;
Pt(double x=0,double y=0) :x(x),y(y) {};
};
typedef Pt vec; vec operator - (Pt a,Pt b) { return vec(a.x-b.x,a.y-b.y); }
vec operator + (vec a,vec b) { return vec(a.x+b.x,a.y+b.y); }
bool operator == (Pt a,Pt b) {
return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;
}
bool operator < (const Pt& a,const Pt& b) {
return a.x<b.x || (a.x==b.x && a.y<b.y);
} vec rotate(vec a,double x) {
return vec(a.x*cos(x)-a.y*sin(x),a.x*sin(x)+a.y*cos(x));
}
double cross(vec a,vec b) { return a.x*b.y-a.y*b.x; }
double dist(Pt a,Pt b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
} vector<Pt> ConvexHull(vector<Pt> p) {
sort(p.begin(),p.end());
p.erase(unique(p.begin(),p.end()),p.end());
int n=p.size() , m=0;
vector<Pt> ch(n+1);
for(int i=0;i<n;i++) {
while(m>1 && cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
ch[m++]=p[i];
}
int k=m;
for(int i=n-2;i>=0;i--) {
while(m>k && cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
ch[m++]=p[i];
}
if(n>1) m--;
ch.resize(m); return ch;
}
半平面交:
//半平面交 const int N = 305;
const double bond = 100001;
const double eps = 1e-10; struct Pt {
double x,y;
Pt (double x=0,double y=0):x(x),y(y){}
};
typedef Pt vec; vec operator + (Pt a,Pt b) { return vec(a.x+b.x,a.y+b.y); }
vec operator - (Pt a,Pt b) { return vec(a.x-b.x,a.y-b.y); }
vec operator * (Pt a,double p) { return vec(a.x*p,a.y*p); } double cross(Pt a,Pt b) { return a.x*b.y-a.y*b.x; } struct Line {
Pt p; vec v; double ang;
Line () {}
Line (Pt p,vec v) :p(p),v(v){ ang=atan2(v.y,v.x); }
bool operator < (const Line& rhs) const {
return ang<rhs.ang;
}
}; bool onleft(Line L,Pt p) { return cross(L.v,p-L.p)>0; }
Pt LineInter(Line a,Line b)
{
vec u=a.p-b.p;
double t=cross(b.v,u)/cross(a.v,b.v);
return a.p+a.v*t;
}
vector<Pt> HPI(vector<Line> L)
{
int n=L.size();
sort(L.begin(),L.end());
int f,r;
vector<Pt> p(n) , ans;
vector<Line> q(n);
q[f=r=0]=L[0];
for(int i=1;i<n;i++) {
while(f<r&&!onleft(L[i],p[r-1])) r--;
while(f<r&&!onleft(L[i],p[f])) f++;
q[++r]=L[i];
if(fabs(cross(q[r].v,q[r-1].v))<eps) {
r--;
if(onleft(q[r],L[i].p)) q[r]=L[i];
}
if(f<r) p[r-1]=LineInter(q[r-1],q[r]);
}
while(f<r&&!onleft(q[f],p[r-1])) r--;
if(r-f<=1) return ans;
p[r]=LineInter(q[r],q[f]);
for(int i=f;i<=r;i++) ans.push_back(p[i]);
return ans;
}
[OI]省选前模板整理的更多相关文章
- SDOI2019 省选前模板整理
目录 计算几何✔ DP 斜率优化✔ 四边形不等式✔ 轮廓线DP✘ 各种分治 CDQ分治✔ 点分治✔ 整体二分✔ 数据结构 线段树合并✔ 分块✔ K-D Tree LCT 可持久化Trie✔ Splay ...
- NOIP前模板整理
图 最短路径 #include <queue> #define N 1000 typedef long long ll; using namespace std; int d[N], w[ ...
- [TaskList] 省选前板子补完计划
省选前本子补完计划 [ ] 带权并查集 [ ] 树上莫队 - UOJ58 [WC2013]糖果公园 loj2485「CEOI2017」Chase
- 省选前的JOI
RT,发现找不到题,于是又开了新坑 JOI特色:重思考,代码难度(相比NOI系列)基本没有 (省选前到处挖坑2333) JOI 2017 Final 焚风现象 差分,莫得了 (不是看到200ms就tm ...
- 省选前的th题
沙茶博主终于整完了知识点并学完了早该在NOIP之前学的知识们 于是终于开始见题了,之前那个奇怪的题单的结果就是这个了 题目按沙茶博主的做题顺序排序 个人感觉(暂时)意义不大的已被自动忽略 洛谷 491 ...
- 字符串系列——KMP模板整理
KMP模板整理 KMP与扩展KMP: /*vs 2017/ vs code以外编译器,去掉windows.h头文件和system("pause");*/ #include<i ...
- ACM算法模板整理
史诗级ACM模板整理 基本语法 字符串函数 istream& getline (char* s, streamsize n ); istream& getline (char* s, ...
- 解决el-tree lazy懒加载时,连续勾选前两个子节点后第二次进入默认选中时,将父节点也勾选的问题
在用到el-tree的懒加载和默认勾选功能时,若第一次勾选前几个连续节点,第二次进入默认勾选时,由于el-tree子节点尚未完全加载(只加载出来前几个),默认勾选已经开始(已加载出来的子节点被默认勾选 ...
- 【学习笔记】OI模板整理
CSP2019前夕整理一下模板,顺便供之后使用 0. 非算法内容 0.1. 读入优化 描述: 使用getchar()实现的读入优化. 代码: inline int read() { int x=0; ...
随机推荐
- Alpha阶段敏捷冲刺②
1.提供当天站立式会议照片一张 每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 购买云服务器 注册账号 界面布局初步规划 今天计划完成的工作. 界面雏 ...
- mysql 时间格式化参数表笔记
DATE_FORMAT() 函数用于以不同的格式显示日期/时间数据. 语法: DATE_FORMAT(date,format) 实例: DATE_FORMAT(NOW(),'%b %d %Y %h:% ...
- [转帖]InfiniBand技术和协议架构分析
InfiniBand技术和协议架构分析 2017年06月06日 20:54:16 Hardy晗狄 阅读数:15207 标签: 云计算存储Infiniband 更多 个人分类: 存储云计算 版权声明 ...
- ACM数论之旅17---反演定理 第一回 二项式反演(神说要有光 于是就有了光(´・ω・`))
终于讲到反演定理了,反演定理这种东西记一下公式就好了,反正我是证明不出来的~(-o ̄▽ ̄)-o 首先,著名的反演公式 我先简单的写一下o( ̄ヘ ̄*o) 比如下面这个公式 f(n) = g(1) + g ...
- HDU3046_Pleasant sheep and big big wolf
给一个n*m的数字阵,1表示羊的位置,2表示狼的位置,0表示没有东西,可以通过.在每个格子的4边都可以建立围栏,有围栏的话狼是不能通过的. 现在求最少建立多少围栏能够保证狼无法接触到羊. 题目的模型很 ...
- jmeter发送json数据,报405、400错误解决方案
1.405错误解决方案:添加HTTP信息头管理器(错误因数:发送格式未设置) 2.400错误解决方案:json文本格式有误(注意:换行.空格等)解决方案:对照json文本数据(错误因数:发送的json ...
- C#:system.collections.generic(泛型)
1. array是一个固定长度的,如果要动态的存储的话就不行了,虽然 System.Collections.ArrayList(),是一个动态的存储的容器,但是没有对存储中的数据进行一个约束,所以非泛 ...
- 【CF995F】Cowmpany Cowmpensation(动态规划,拉格朗日插值)
[CF995F]Cowmpany Cowmpensation(多项式插值) 题面 洛谷 CF 题解 我们假装结果是一个关于\(D\)的\(n\)次多项式, 那么,先\(dp\)暴力求解颜色数为\(0. ...
- 20165218 《网络对抗技术》Exp1 逆向及Bof基础
Exp1 逆向及Bof基础 基础知识 1. NOP, JNE, JE, JMP, CMP汇编指令的机器码 指令 机器码 NOP NOP指令即"空指令",在x86的CPU中机器码为0 ...
- Nginx访问日志分析
nginx默认的日志格式 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$sta ...