OI各类模板
四边形不等式
定义函数 \(f(l,r)\) 满足四边形不等式为:对于所有 $ l \le l' \le r' \le r $ ,满足 $f(l,r) \ge f(l',r') , f(l,r)+f(l',r') \ge f(l,r')+f(l',r) $
对于状态转移方程 $f(i,j)=min \begin{Bmatrix} f(i,k)+f(k+1,j) \end{Bmatrix}+w(i,j) | i<=k<j $ ,有如下结论:
- 若w满足四边形不等式,则f满足四边形不等式
- 设s(l,r)表示区间[l,r]取最优值时k的值则:
\[s(l,r-1) \le s(l,r) \le s(l+1,r)
\]
要点:整体不小于局部,包含不小于相交,长度减1求范围。
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int oo=1e9+7;
const int maxn=2007;
int a[maxn],sum[maxn];
int n,Fi[maxn][maxn],Fa[maxn][maxn],s[maxn][maxn];
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i]; s[i][i]=i; a[i+n]=a[i];
}
for(int i=1+n;i<=n*2;i++)
{
sum[i]=sum[i-1]+a[i];
s[i][i]=i;
}
for(int i=n*2-1;i>=1;i--)
for(int j=i+1;j<=n*2;j++)
{
int &pos=s[i][j],&val=Fi[i][j]; val=oo;
Fa[i][j]=max(Fa[i+1][j],Fa[i][j-1])+(sum[j]-sum[i-1]);
for(int k=s[i][j-1];k<=s[i+1][j];k++)
{
int tmp=Fi[i][k]+Fi[k+1][j]+(sum[j]-sum[i-1]);
if(tmp<val) val=tmp,pos=k;
}
}
int res_ma=0,res_mi=oo;
for(int i=1;i<=n;i++)
{
res_ma=max(res_ma,Fa[i][i+n-1]);
res_mi=min(res_mi,Fi[i][i+n-1]);
}
printf("%d\n%d\n",res_mi,res_ma);
return 0;
}
斜率优化
manacher算法
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=51000005;
int n,R[maxn],ans;
char a[maxn],s[maxn<<1];
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
scanf("%s",a); n=strlen(a);
s[0]=s[1]='#';
for(int i=0;i<n;i++) s[i*2+2]=a[i],s[i*2+3]='#';
n=2*n+2;
int maxright=0,mid=0;
for(int i=1;i<n;i++)
{
if(i<maxright) R[i]=min(R[mid*2-i],R[mid]+mid-i);
else R[i]=1;
while(s[i-R[i]]==s[i+R[i]]) ++R[i];
if(R[i]+i>maxright) { maxright=R[i]+i; mid=i; }
}
ans=1;
for(int i=0;i<n;i++) ans=max(ans,R[i]-1);
printf("%d\n",ans);
return 0;
}
KMP 算法
字符串的最小表示
例子:【模板】字符串的最小表示
代码:
#include<cstdio>
#include<cstring>
const int maxn=1e7+5;
char s[maxn];
int n;
int getmin(char *s)
{
int i=0,j=1,k=0,t;
while(i<n&&j<n&&k<n)
{
t=s[(i+k)%n]-s[(j+k)%n];
if(!t) k++;
else
{
if(t>0) i+=k+1;
else j+=k+1;
if(i==j) j++;
k=0;
}
}
return (i<j?i:j)%n;
}
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
scanf("%s",s); n=strlen(s);
printf("%d\n",getmin(s));
return 0;
}
AC自动机
代码:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxsize=1e6+5;
const int sigsize=26;
int n; char str[maxsize];
struct ACMachine
{
int e[maxsize][sigsize],f[maxsize],val[maxsize],last[maxsize],cnt;
void insert(char *s)
{
int n=strlen(s),p=0;
for(int i=0;i<n;i++)
{
if(!e[p][s[i]-'a']) e[p][s[i]-'a']=++cnt;
p=e[p][s[i]-'a'];
}
++val[p];
}
void build()
{
queue<int> Q;
for(int c=0;c<sigsize;c++) if(e[0][c]) Q.push(e[0][c]);
while(Q.size())
{
int u=Q.front(),k=f[u]; Q.pop();
for(int c=0;c<sigsize;c++)
{
int &v=e[u][c];
if(!v) { v=e[k][c]; continue; }
Q.push(v);
f[v]=e[k][c]; last[v]=val[f[v]]?f[v]:last[f[v]];
}
}
}
int query(char *s)
{
int n=strlen(s),p=0,res=0;
for(int i=0;i<n;i++)
{
p=e[p][s[i]-'a'];
res+=val[p]; val[p]=0;
int v=p;
while(last[v])
{
v=last[v];
res+=val[v]; val[v]=0;
}
}
return res;
}
}AC;
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
scanf("%d",&n);
while(n-->0) scanf("%s",str),AC.insert(str);
AC.build();
scanf("%s",str);
printf("%d\n",AC.query(str));
return 0;
}
DLX算法
关键代码:
struct DLX
{
int n,sz;
int s[maxn];
int row[maxnode],col[maxnode];
int U[maxnode],D[maxnode],L[maxnode],R[maxnode];
int ansd,ans[300];
void init(int n)
{
this->n=n; sz=n+1;
memset(s,0,sizeof(s));
for(int i=0;i<=n;i++) { U[i]=i; D[i]=i; L[i]=i-1; R[i]=i+1; }
L[0]=n; R[n]=0;
}
inline void push_back(int r,const vector<int> &cols)
{
int first=sz,szc=cols.size();
for(int i=0;i<szc;i++)
{
int c=cols[i];
L[sz]=sz-1; R[sz]=sz+1; D[sz]=c; U[sz]=U[c];
D[U[sz]]=sz; U[c]=sz;
row[sz]=r; col[sz]=c;
++s[c]; ++sz;
}
R[sz-1]=first; L[first]=sz-1;
}
#define For(i,A,s) for(int i=A[s];i!=s;i=A[i])
inline void remove(int c)
{
L[R[c]]=L[c]; R[L[c]]=R[c];
For(i,D,c) For(j,R,i) { U[D[j]]=U[j]; D[U[j]]=D[j]; --s[col[j]]; }
}
inline void restore(int c)
{
For(i,U,c) For(j,L,i) { ++s[col[j]]; U[D[j]]=j; D[U[j]]=j; }
L[R[c]]=c; R[L[c]]=c;
}
bool dfs(int d)
{
if(R[0]==0) { ansd=d; return true; }
int c=R[0];
For(i,R,0) if(s[i]<s[c]) c=i;
remove(c);
For(i,D,c)
{
ans[d]=row[i];
For(j,R,i) remove(col[j]);
if(dfs(d+1)) return true;
For(j,L,i) restore(col[j]);
}
restore(c);
return false;
}
bool solve(vector<int> &res)
{
res.clear();
if(!dfs(0)) return false;
for(int i=0;i<ansd;i++) res.push_back(ans[i]);
return true;
}
};
欧拉回路
int cnt=0,res[maxn];
void dfs(int u)
{
for(int it=G[u];it;it=e[it].next)
if(e[it].v>=0)//not deleted
{
int v=e[it].v;
du[u]--; du[e[it].v]--;
e[it].v=-1;
e[it^1].v=-1;
dfs(v);
}
res[cnt++]=u;
}
while(cnt>0) printf("%d ",res[--cnt]);
矩阵树定理
度数矩阵D:是一个\(N\times N\)的矩阵,其中\(D[i][j]=0 (i \neq j),D[i][i]=\)节点\(i\)的度数。
邻接矩阵A:是一个\(N\times N\)的矩阵,其中\(A[i][j]=\)点\(i,j\)之间的边数。
基尔霍夫Kirchhoff矩阵K=D-A
该无向图的生成树的个数等于矩阵K去掉一行一列后的行列式的绝对值。
最小生成树(瓶颈生成树)
代码:
Prim:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=5005;
const int maxm=200005;
struct Edge { int v,w; Edge *next; };
Edge *G[maxn],mem[maxm*2],*ecnt=mem;
inline void AddEdge(int u,int v,int w) { ecnt->v=v; ecnt->w=w; ecnt->next=G[u]; G[u]=ecnt++; }
int n,m,inq,res;
typedef pair<int,int> PII;
#define mkp make_pair
priority_queue<PII,vector<PII>,greater<PII> > Q;
int dis[maxn];
bool vis[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
AddEdge(a,b,c); AddEdge(b,a,c);
}
memset(dis,127,sizeof(dis));
dis[1]=0;
Q.push(mkp(0,1));
while(!Q.empty()&&inq<n)
{
int u=Q.top().second,w=Q.top().first;
Q.pop();
if(vis[u]) continue;
vis[u]=true;
res+=w;
inq++;
for(Edge *it=G[u];it;it=it->next)
if(it->w<dis[it->v]) dis[it->v]=it->w,Q.push(mkp(dis[it->v],it->v));
}
if(inq==n) printf("%d\n",res);
else printf("orz\n");
return 0;
}
有向图的强连通分量
例子:UVA12167 Proving Equivalences
关键代码:
vector<int> G[maxn];
int dfn[maxn],lowlink[maxn],sccno[maxn],dfs_cnt,scc_cnt;
stack<int> S;
void dfs(int u)
{
dfn[u]=lowlink[u]=++dfs_cnt;
S.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!dfn[v])
{
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if(!sccno[v]) lowlink[u]=min(lowlink[u],dfn[v]);
}
if(lowlink[u]==dfn[u])
{
scc_cnt++;
while(true)
{
int x=S.top(); S.pop();
sccno[x]=scc_cnt;
if(x==u) break;
}
}
}
dfs_cnt=0; scc_cnt=0;
memset(sccno,0,sizeof(sccno));
memset(dfn,0,sizeof(dfn));
for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
无向图最小环
关键代码:
for(int k=1;k<=n;++k)
{
for(int i=1;i<k;++i)
for(int j=1;j<i;++j)
if((dis[i][j]^oo)&&(G[j][k]^oo)&&(G[k][i]^oo))
res=min(res,dis[i][j]+G[j][k]+G[k][i]);
for(int i=1;i<=n;++i)
for(int j=1;j<i;++j)
{
int tmp=dis[i][k]+dis[k][j];
if(tmp<dis[i][j]) dis[i][j]=dis[j][i]=tmp;
}
}
AOE网关键路径
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
template<typename T> inline void read(T& t)
{
t=0; int ch,f=false;
while(ch=getchar(),!((ch>='0'&&ch<='9')||ch=='-'));
if(ch=='-') f=true,ch=getchar();
t=ch^48;
while(ch=getchar(),ch>='0'&&ch<='9') t=t*10+(ch^48);
if(f) t=-t;
}
template<typename T,typename... Args> inline void read(T& t,Args&... args) { read(t); read(args...); }
const int maxn=1005;
const int maxm=1000005;
const int oo=0x3f3f3f3f;
struct Edge { int v,w; Edge *next; };
Edge mem[maxm],*G[maxn],*ecnt=mem;
inline void AddEdge(int u,int v,int w) { ecnt->v=v; ecnt->w=w; ecnt->next=G[u]; G[u]=ecnt++; }
int du[maxn],stk1[maxn],top1,stk2[maxn],top2;
int ve[maxn],vl[maxn];
int main()
{
int n,m,u,v,w,res=0;
read(n,m);
while(m-->0)
{
read(u,v,w);
AddEdge(u,v,w);
++du[v];
}
for(int i=1;i<=n;i++) if(!du[i]) stk2[top2++]=stk1[top1++]=i;
while(top1>0)
{
int u=stk1[--top1];
for(Edge *it=G[u];it;it=it->next)
{
ve[it->v]=max(ve[it->v],ve[u]+it->w);
if(--du[it->v]==0) stk2[top2++]=stk1[top1++]=it->v;
}
}
memset(vl,oo,sizeof(vl));
vl[stk2[n-1]]=ve[stk2[n-1]];
while(top2>0)
{
int u=stk2[--top2];
for(Edge *it=G[u];it;it=it->next) vl[u]=min(vl[u],vl[it->v]-it->w);
}
for(int i=1;i<=n;i++) for(Edge *it=G[i];it;it=it->next)
if(ve[i]/*ee*/==vl[it->v]-it->w/*el*/) res+=it->w;
printf("%d\n",res);
return 0;
}
后缀数组
概念:
- 后缀i:从第i个字符开始的后缀
- sa[i]:第i小的后缀
- rank[i]:后缀i在sa中的下标
- height[i]=LCP(后缀sa[i],后缀sa[i-1])
- 后缀j和后缀k的LCP=RMQ(height,rank[j]+1,rank[k])
关键代码:
char s[maxn];
int sa[maxn],t[maxn],t2[maxn],c[maxn],n;
int rnk[maxn],height[maxn];
void build_sa(int sig)
{
int *x=t,*y=t2;
memset(c,0,sizeof(c));
for(int i=0;i<n;i++) c[x[i]=s[i]]++;
for(int i=1;i<sig;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;i++) y[p++]=i;
for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
memset(c,0,sizeof(c));
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=1;i<sig;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1; x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++);
if(p>=n) break;
sig=p;
}
}
void getHeight()
{
int i,j,k=0;
for(i=0;i<n;i++) rnk[sa[i]]=i;
for(i=0;i<n;i++)
{
if(rnk[i]==0) continue;
if(k) k--;
j=sa[rnk[i]-1];
while(i+k<n&&j+k<n&&s[i+k]==s[j+k]) k++;
height[rnk[i]]=k;
}
}
点分治
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10005;
struct Edge { int v,w; Edge *next; };
Edge mem[maxn*2],*G[maxn],*ecnt=mem;
inline void AddEdge(int u,int v,int w) { ecnt->v=v; ecnt->w=w; ecnt->next=G[u]; G[u]=ecnt++; }
int n,m,k,res,Siz,rt,cnt;
bool vis[maxn];
int f[maxn],sz[maxn],dis[maxn];
void GetRoot(int u,int fa)
{
f[u]=0; sz[u]=1;
for(Edge *it=G[u];it;it=it->next)
{
int v=it->v;
if(vis[v]||v==fa) continue;
GetRoot(v,u);
f[u]=max(f[u],sz[v]); sz[u]+=sz[v];
}
f[u]=max(f[u],Siz-f[u]);
if(f[u]<f[rt]) rt=u;
}
void GetDis(int u,int fa,int d)
{
for(Edge *it=G[u];it;it=it->next)
{
int v=it->v;
if(vis[v]||v==fa) continue;
dis[++cnt]=d+it->w;
GetDis(v,u,dis[cnt]);
}
}
int GetAns(int u,int d)
{
dis[cnt=1]=d;
GetDis(u,0,d);
sort(dis+1,dis+1+cnt);
int l=1,res=0;
while(l<cnt&&dis[l]+dis[cnt]<k) ++l;
while(l<cnt&&k-dis[l]>=dis[l])
{
auto it=equal_range(dis+l+1,dis+cnt+1,k-dis[l]);
res+=it.second-it.first;
++l;
}
return res;
}
void dfs(int u)
{
vis[u]=true; res+=GetAns(u,0);
for(Edge *it=G[u];it;it=it->next)
{
int v=it->v;
if(vis[v]) continue;
res-=GetAns(v,it->w);
Siz=sz[v]; rt=0;
GetRoot(v,u);
dfs(v);
}
}
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
int a,b,c;
for(int i=0;i<n-1;i++)
{
scanf("%d%d%d",&a,&b,&c);
AddEdge(a,b,c); AddEdge(b,a,c);
}
while(m-->0)
{
scanf("%d",&k);
res=0; memset(vis,0,sizeof(vis)); Siz=n; sz[0]=1e9+7;
dfs(1);
puts(res?"AYE":"NAY");
}
return 0;
}
01分数规划
算法模板:
- 二分法(通用算法,验证解快时使用)
L:=...;R:=...;
Repeat
Mid:=(L+R)/2;
For I=1..X do D[i]:=A[i]-Mid*B[i];//根据Mid计算D数组
if 检查(Mid)成功 then L:=Mid
else R:=Mid;
Until abs(L-R)<Eps;
- Dinkelbach算法(求解快时使用)
L:=随便什么东西;
Repeat
Ans:=L;
For I=1..X do D[i]:=A[i]-L*B[i];//根据L计算D数组
检查解并记录;
p:=0;q:=0;
for I=每一个元素 do
如果元素I在解中
begin
p:=p+A[i];q:=q+B[i];
end;
L:=p/q;//更新解
Until abs(Ans-L)<Eps;
线性筛与积性函数
算法模板:
f[1]=1; memset(isp,true,sizeof(isp));
cnt=0;
for(int i=2;i<=n;i++)
{
if(isp[i])
{
p[cnt++]=i;
根据定义初始化;//eg. phi[i]=i-1;
}
for(int j=0;j<cnt&&i*p[j]<=n;j++)
{
isp[i*p[j]]=false;
if(i%p[j]==0)
{
特殊处理;//eg. phi[i*p[j]]=phi[i]*p[j];
break;
}
else f[i*p[j]]=f[i]*f[p[j]];
}
}
long long 乘法取模
inline LL mmul(LL a, LL b, LL m)
{
LL d=((long double)a/m*b+0.5);//注意!不加0.5可能会有精度问题!
LL r=a*b-d*m;
return r<0?r+m:r;
}
分组背包
伪代码:
for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]}
泛化物品
定义:有一个物品,它消耗i的代价时的收益是G[i]
- 泛化物品的和:合并两个泛化物品的运算
G[i]=max(G1[j-k]+G2[k]) (C>=j>=k>=0)
- 泛化物品与普通物品的和:普通背包
- 泛化物品的并(貌似用不到,暂时跳过)
树形依赖背包(后序遍历优化)
代码:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
template<typename T> inline void read(T& t)
{
t=0; int ch,f=false;
while(ch=getchar(),!((ch>='0'&&ch<='9')||ch=='-'));
if(ch=='-') f=true,ch=getchar();
t=ch^48;
while(ch=getchar(),ch>='0'&&ch<='9') t=t*10+(ch^48);
if(f) t=-t;
}
template<typename T,typename... Args> inline void read(T& t,Args&... args) { read(t); read(args...); }
const int maxn=65;
const int maxm=32005;
int f[maxn][maxm];
vector<int> son[maxn];
int V[maxn],W[maxn];
int n,m,v,p,q;
int sz[maxn],suf[maxn],cnt;
void dfs(int u)
{
sz[u]=1;
for(int i=0;i<son[u].size();i++) { dfs(son[u][i]); sz[u]+=sz[son[u][i]]; }
suf[++cnt]=u;
}
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
read(m,n);
for(int i=1;i<=n;i++)
{
read(v,p,q);
V[i]=v*p; W[i]=v; son[q].push_back(i);
}
dfs(0);
for(int i=1;i<=cnt;i++)
{
int now=suf[i];
for(int j=m;j>=0;j--)
if(j>=W[now]) f[i][j]=max(f[i-sz[now]][j],f[i-1][j-W[now]]+V[now]);
else f[i][j]=f[i-sz[now]][j];
}
printf("%d\n",f[cnt][m]);
return 0;
}
计算几何:传送门
数论:传送门
Dinic
代码:
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
template<typename T> inline void read(T& t)
{
t=0; bool f=false; char ch;
while(ch=getchar(),!((ch>='0'&&ch<='9')||ch=='-'));
if(ch=='-') f=true,ch=getchar();
t=ch-'0';
while(ch=getchar(),ch>='0'&&ch<='9') t=t*10+ch-'0';
if(f) t=-t;
}
template<typename T,typename... Args> inline void read(T& t,Args&... args) { read(t); read(args...); }
const int maxn=10005;
const int oo=1e9+7;
struct Edge { int from,to,cap,flow; };
struct Dinic
{
int n,m,s,t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn],pos[maxn];
inline void AddEdge(int u,int v,int c)
{
edges.push_back((Edge){u,v,c,0});
edges.push_back((Edge){v,u,0,0});
m=edges.size();
G[u].push_back(m-2);
G[v].push_back(m-1);
}
inline bool BFS()
{
memset(vis,0,sizeof(vis)); memset(d,0x3f,sizeof(d));
queue<int> Q;
Q.push(s); vis[s]=true; d[s]=0;
while(Q.size())
{
int u=Q.front(); Q.pop();
for(int i=0;i<G[u].size();i++)
{
Edge &e=edges[G[u][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to]=true;
d[e.to]=d[u]+1;
Q.push(e.to);
}
}
}
return vis[t];
}
inline int DFS(int u,int a)
{
if(u==t||a==0) return a;
int flow=0,f;
for(int &i=pos[u];i<G[u].size();i++)
{
Edge &e=edges[G[u][i]];
if(d[u]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
{
e.flow+=f; flow+=f;
edges[G[u][i]^1].flow-=f; a-=f;
if(a==0) break;
}
}
return flow;
}
int MaxFlow(int s,int t)
{
this->s=s; this->t=t;
int flow=0;
while(BFS())
{
memset(pos,0,sizeof(pos));
flow+=DFS(s,oo);
}
return flow;
}
}dinic;
int n,m,s,t,u,v,c;
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
read(n,m,s,t);
while(m-->0)
{
read(u,v,c);
dinic.AddEdge(u,v,c);
}
printf("%d\n",dinic.MaxFlow(s,t));
return 0;
}
快排
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int maxn=100005;
int n,a[maxn];
void quicksort(int L,int R)
{
if(L>=R) return;
int i=L,j=R;
swap(a[L],a[L+rand()%(R-L+1)]);
while(i<j)
{
while(j>i&&a[j]>=a[L]) j--;
while(j>i&&a[i]<=a[L]) i++;
swap(a[i],i==j?a[L]:a[j]);
}
quicksort(L,i-1);
quicksort(i+1,R);
}
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
srand(187);
quicksort(0,n-1);
for(int i=0;i<n;i++) printf("%d ",a[i]); puts("");
return 0;
}
归并排序 & 求逆序对
#include<cstdio>
#include<cstring>
const int maxn=5e5+5;
int n; long long res;
int a[maxn],b[maxn];
void GB(int *a,int *b,int len)
{
if(len<=1) return;
int M=len/2,p1=0,p2=M,p=0;
GB(a,b,M); GB(a+M,b+M,len-M);
while(p1<M&&p2<len)
{
if(a[p1]<=a[p2]) b[p++]=a[p1++];
else res+=M-p1,b[p++]=a[p2++];
}
while(p1<M) b[p++]=a[p1++];
while(p2<len) b[p++]=a[p2++];
memcpy(a,b,len<<2);
}
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
GB(a,b,n);
printf("%lld\n",res);
return 0;
}
基数排序
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,a[maxn],b[maxn],cnt[10];
void bksort()
{
int mx=a[0];
for(int i=1;i<n;i++) mx=max(mx,a[i]);
for(int exp=1;mx/exp>0;exp*=10)
{
for(int i=0;i<10;i++) cnt[i]=0;
for(int i=0;i<n;i++) cnt[a[i]/exp%10]++;
for(int i=1;i<10;i++) cnt[i]+=cnt[i-1];
for(int i=n-1;i>=0;i--) b[--cnt[a[i]/exp%10]]=a[i];
memcpy(a,b,n<<2);
}
}
int main()
{
#ifdef local
freopen("pro.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
bksort();
for(int i=0;i<n;i++) printf("%d ",a[i]); puts("");
return 0;
}
LCA
Tarjan
#include<cstdio>
template<typename T>
inline void read(T& t)
{
t=0; bool f=false; char ch;
while(ch=getchar(),!((ch>='0'&&ch<='9')||ch=='-'));
if(ch=='-') f=true,ch=getchar();
t=ch-'0';
while(ch=getchar(),ch>='0'&&ch<='9') t=t*10+ch-'0';
if(f) t=-t;
}
template<typename T,typename... Args>
inline void read(T& t,Args&... args)
{
read(t); read(args...);
}
template<typename T>
inline void write(T t)
{
if(t==0) { putchar('0'); return; }
char stk[50]; int top;
if(t<0) putchar('-'),t=-t;
while(t>0) stk[top++]=t%10+'0',t/=10;
while(top>0) putchar(stk[--top]);
}
const int maxn=500005;
const int maxm=500000*2+5;
struct Rec { int to,lca; Rec *next; };
Rec edge[maxm],*E[maxn],*ecnt=edge;
Rec query[maxm],*Q[maxn],*qcnt=query;
inline void AddEdge(Rec **G,Rec* &ecnt,int from,int to)
{ ecnt->to=to; ecnt->next=G[from]; G[from]=ecnt++; }
int n,m,s;
bool vis[maxn];
int fa[maxn];
inline int ff(int x)
{
int a=x,b;
while(x!=fa[x]) x=fa[x];
while(a!=x)
{
b=fa[a];
fa[a]=x;
a=b;
}
return x;
}
void dfs(int u)
{
fa[u]=u;
vis[u]=true;
for(Rec *it=E[u];it;it=it->next)
if(!vis[it->to])
{
dfs(it->to);
fa[it->to]=u;
}
for(Rec *it=Q[u];it;it=it->next)
if(vis[it->to])
{
it->lca=ff(it->to);
(query+((it-query)^1))->lca=it->lca;
}
}
int main()
{
read(n,m,s);
for(int i=0;i<n-1;i++)
{
int a,b; read(a,b);
AddEdge(E,ecnt,a,b); AddEdge(E,ecnt,b,a);
}
for(int i=0;i<m;i++)
{
int a,b; read(a,b);
AddEdge(Q,qcnt,a,b); AddEdge(Q,qcnt,b,a);
}
dfs(s);
for(int i=0;i<m;i++) { write(query[i*2].lca); putchar('\n'); }
return 0;
}
倍增
#include<cstdio>
#include<vector>
#include<cstdlib>
using namespace std;
const int maxn=500005;
int n,m,s;
vector<int> G[maxn];
int dep[maxn],anc[maxn][30];
void cal(int o,int fa)
{
dep[o]=dep[anc[o][0]]+1;
for(int i=1;i<=25;i++) anc[o][i]=anc[anc[o][i-1]][i-1];
for(int ch:G[o])
if(ch!=fa)
{
anc[ch][0]=o;
cal(ch,o);
}
}
inline int getLCA(int a,int b)
{
if(a==b) return a;
if(dep[b]>dep[a]) swap(a,b);
for(int i=25;i>=0;i--)
if(dep[anc[a][i]]>=dep[b]) a=anc[a][i];
if(a==b) return a;
for(int i=25;i>=0;i--)
if(anc[a][i]!=anc[b][i]) a=anc[a][i],b=anc[b][i];
return anc[a][0];
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=0;i<n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y); G[y].push_back(x);
}
cal(s,0);
while(m-->0)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",getLCA(x,y));
}
return 0;
}
RMQ
- 构造这颗树的欧拉序(每次经过一个节点都要记录下来,包括回退时)
- 在(u,v)的欧拉序中第一次出现的位置之间的深度最小的点即为LCA
欧拉序:
vector<int> a;
void dfs(int u)
{
a.push_back(u);
for(Edge *it=G[u];it;it=it->nxt)
{
dfs(it->v);
a.push_back(u);
}
}
本作品由happyZYM采用知识共享 署名-非商业性使用-相同方式共享 4.0 (CC BY-NC-SA 4.0) 国际许可协议(镜像(简单版)镜像(完整版))进行许可。
转载请注明出处:https://www.cnblogs.com/happyZYM/p/11379879.html (近乎)全文转载而非引用的请在文首添加出处链接。