#模板整理
是一些想要会打的模板
持更ovo
高精度
inline void Init(int a[])//输入
{
string s;
cin>>s;
int len=s.length();
for(re int i=0;i<len;i++)
{
int j=(len-i+3)/4;
a[j]=a[j]*10+s[i]-'0';
}
a[0]=(len+3)/4;
}
inline void Print(int a[])//输出
{
cout<<a[a[0]];
for(re int i=a[0]-1;i>0;i--)
for(re int j=base/10;j>0;j/=10)
cout<<a[i]/j%10;
}
inline int Comp(int a[],int b[])//比较大小 相等输出0,a>b输出1,a<b输出-1
{
if(a[0]>b[0]) return 1;
if(a[0]<b[0]) return -1;
for(re int i=a[0];i>=1;i--)
if(a[i]>b[i])
return 1;
else if(a[i]<b[i])
return -1;
return 0;
}
inline void Div(int a[],int k)//高精除以低精
{
int t=0;
for(re int i=a[0];i>=1;i--)
{
t=t*base+a[i];
a[i]=t/k;
t%=k;
}
while(a[a[0]]==0&&a[0]>0)
a[0]--;
}
inline void Minus(int a[],int b[])//高精减
{
for(re int i=1;i<=a[0];i++)
{
a[i]-=b[i];
if(a[i]<0)
{
a[i+1]--;
a[i]+=base;
}
while(a[a[0]]==0&&a[0]>0)
a[0]--;
}
}
inline void MulHigh(int a[],int b[])//高精乘高精
{
memset(c,0,sizeof(c));
for(re int i=1;i<=a[0];i++)
for(re int j=1;j<=b[0];j++)
{
c[i+j-1]+=a[i]*b[j];
c[i+j]+=c[i+j-1]/base;
c[i+j-1]%=base;
}
c[0]=a[0]+b[0];
while(c[c[0]]==0&&c[0]>0)
c[0]--;
for(re int i=0;i<=c[0];i++)
a[i]=c[i];
}
inline void MulLow(int a[],int k)//高精乘低精
{
for(re int i=1;i<=a[0];i++)
a[i]*=k;
for(re int i=1;i<=a[0];i++)
{
a[i+1]+=a[i]/base;
a[i]%=base;
}
while(a[a[0]+1]>0)
{
a[0]++;
a[a[0]+1]=a[a[0]]/base;
a[a[0]]%=base;
}
}
同余定理(扩展欧几里得求特解)
void Exgcd(int a,int b,int &d,int &x,int &y)
{
if(b==0)
{
d=a;
x=c/a;
y=0;
}
else
{
int x1,y1;
Exgcd(b,a%b,d,x1,y1);
x=y1;
y=x1-a/b*y1;
}
}
若需求\(1\sim b\)范围内的最小正整数解,则
x=(x%d+d)%d;
快速幂
base=b;
while(p)
{
if(p&1)
ans=(ans%k*base%k)%k;
p>>=1;
base=(base%k*base%k)%k;
}
线性筛(欧拉筛)
for(int i=2;i<=n;i++)
{
if(!v[i])
{
v[i]=i;
p[++total]=i;
}
for(int j=1;j<=total;j++)
{
if(p[j]>v[i]||p[j]*i>n) break;
v[i*p[j]]=p[j];
}
}
埃氏筛
for(int i=2;i<=n;i++)
{
if(v[i]) continue;
for(int j=i;j*i<=n;j++)
v[i*j]=1;
}
Dijsktra:
priority_queue< pair<int,int> >q;
inline void DJ()
{
memset(dis1,INF,sizeof(dis1));
memset(dis2,INF,sizeof(dis2));
dis1[1]=0;
q.push(make_pair(0,1));
while(!q.empty())
{
int x=q.top().second,dis=q.top().first;
q.pop(),dis=-dis;
if(dis>dis2[x]) continue;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to,z=e[i].w;
if(dis1[y]>dis+z)
dis2[y]=dis1[y],
dis1[y]=dis+z,
q.push(make_pair(-dis1[y],y));
if(dis+z<dis2[y]&&dis+z>dis1[y])
dis2[y]=dis+z,
q.push(make_pair(-dis2[y],y));
}
}
}
SPFA:
inline void SPFA()
{
memset(dis,INF,sizeof(dis));
dis[1]=0,vst[1]=true,q.push(1);
while(!q.empty())
{
int i=q.front();
for(int k=fst[i];k;k=e[k].nxt)
{
int j=e[k].to;
if(dis[j]>dis[i]+e[k].v)
{
dis[j]=dis[i]+e[k].v;
if(!vst[j])
{
q.push(j);
vst[j]=true;
}
}
}
vst[i]=false;
q.pop();
}
}
DFS_SPFA:
inline bool SPFA(int x)
{
v[x]=1;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to,z=e[i].w;
if(dis[y]>dis[x]+z)
{
dis[y]=dis[x]+z;
if(v[y])
return 1;
else if(SPFA(y))
return 1;
}
}
v[x]=0;
return 0;
}
记录入队次数のSPFA:
inline bool SPFA()
{
memset(d,INF,sizeof(d));
memset(v,0,sizeof(v));
memset(cnt,0,sizeof(cnt));
d[s]=0;
q.push(s);
v[s]=1;
while(!q.empty())
{
int x=q.front();q.pop();
v[x]=0;
o[x]=1;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to,z=e[i].w;
if(d[y]>d[x]+z)
{
d[y]=d[x]+z;
if(!v[y])
{
if(++cnt[y]>=n)
return true;
q.push(y);
v[y]=1;
}
}
}
}
return false;
}
线段树基操
const int N=1e5+7;
struct SegmentTree
{
int l,r;
long long sum,add;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum(x) tree[x].sum
#define add(x) tree[x].add
}tree[N<<2];
int n,m;
void build(int p,int l,int r)
{
l(p)=l,r(p)=r;
if(l==r)
{
int h;
read(h);
sum(p)=h;
return ;
}
int mid=(l(p)+r(p))>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
sum(p)=sum(p<<1)+sum(p<<1|1);
}
void spread(int p)
{
if(add(p))
{
sum(p<<1)+=add(p)*(r(p<<1)-l(p<<1)+1);
sum(p<<1|1)+=add(p)*(r(p<<1|1)-l(p<<1|1)+1);
add(p<<1)+=add(p);
add(p<<1|1)+=add(p);
add(p)=0;
}
}
void change(int p,int l,int r,int d)
{
if(l<=l(p)&&r(p)<=r)
{
sum(p)+=(long long)d*(r(p)-l(p)+1);
add(p)+=d;
return ;
}
spread(p);
int mid=(l(p)+r(p))>>1;
if(l<=mid) change(p<<1,l,r,d);
if(mid<r) change(p<<1|1,l,r,d);
sum(p)=sum(p<<1)+sum(p<<1|1);
}
long long ask(int p,int l,int r)
{
if(l<=l(p)&&r(p)<=r) return sum(p);
spread(p);
int mid=(l(p)+r(p))>>1;
long long val=0;
if(l<=mid) val+=ask(p<<1,l,r);
if(mid<r) val+=ask(p<<1|1,l,r);
return val;
}
AC自动机
const int N=7e5+7;
int tree[N][26];
int cnt[N];
int f[N];
int T,n,tot;
string s,w;
inline void Clear()
{
memset(tree,0,sizeof(tree));
memset(cnt,0,sizeof(cnt));
memset(f,0,sizeof(f));
tot=0;
}
inline void insert(string s)
{
int root=0;
for(int i=0;i<s.size();i++)
{
int nxt=s[i]-'a';
if(!tree[root][nxt])
tree[root][nxt]=++tot;
root=tree[root][nxt];
}
cnt[root]++;//当前节点单词数+1
}
inline void GetFail()
{
queue<int>q;
for(int i=0;i<26;i++)
if(tree[0][i])
{
q.push(tree[0][i]);
f[tree[0][i]]=0;
}
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(tree[now][i])
{
f[tree[now][i]]=tree[f[now]][i];
q.push(tree[now][i]);
}
else
tree[now][i]=tree[f[now]][i];
}
}
}
inline int query(string s)
{
int now=0,smx=0;
for(int i=0;i<s.size();i++)
{
now=tree[now][s[i]-'a'];
for(int j=now;cnt[j]!=-1;j=f[j])
{
smx+=cnt[j];
cnt[j]=-1;
}
}
return smx;
}
KMP
const int N=1e6+7;
char s1[N],s2[N];
int nxt[N];
int l1,l2;
int main()
{
cin>>s1+1;
cin>>s2+1;
l1=strlen(s1+1);
l2=strlen(s2+1);
for(int i=2,j=0;i<=l2;i++)
{
while(j&&s2[i]!=s2[j+1]) j=nxt[j];
if(s2[j+1]==s2[i]) j++;
nxt[i]=j;
}
for(int i=1,j=0;i<=l1;i++)
{
while(j>0&&s2[j+1]!=s1[i]) j=nxt[j];
if(s2[j+1]==s1[i]) j++;
if(j==l2)
printf("%d\n",i-l2+1),j=nxt[j];
}
for(int i=1;i<=l2;i++)
printf("%d ",nxt[i]);
return 0;
}
Splay
const int N=1e5+7,INF=23140414;
int n,op,x;
int root,tot;
struct Node
{
int v,fa,ch[2],size,recy;
}e[N];
inline int i(int x)
{
return e[e[x].fa].ch[1]==x;
}
inline void connect(int x,int f,int son)
{
e[x].fa=f;
e[f].ch[son]=x;
}
inline void update(int x)
{
e[x].size=e[x].recy;
e[x].size+=e[e[x].ch[0]].size;
e[x].size+=e[e[x].ch[1]].size;
}
inline void rotate(int x)
{
int f=e[x].fa;
int g_f=e[f].fa;
int locate_f=i(f);
int locate_x=i(x);
int v=e[x].ch[locate_x^1];//旋后u重复儿子,需放到f的空儿子
connect(v,f,locate_x);
connect(f,x,locate_x^1);
connect(x,g_f,locate_f);
update(f);//注意顺序
update(x);
}
inline void Splay(int x,int goal)
{
while(e[x].fa!=goal)
{
int y=e[x].fa;
int z=e[y].fa;
if(z!=goal)
(e[y].ch[0]==x)^(e[z].ch[0]==y)?rotate(x):rotate(y);
rotate(x);
}
if(goal==0)
root=x;
}
inline void Insert(int x)
{
int u=root,f=0;
while(u&&e[u].v!=x) f=u,u=e[u].ch[x>e[u].v];
if(u)
e[u].recy++;
else
{
u=++tot;
if(f)
e[f].ch[x>e[f].v]=u;
e[tot].ch[0]=e[tot].ch[1]=0;
e[tot].fa=f,e[tot].v=x,e[tot].size=e[tot].recy=1;
}
Splay(u,0);
}
inline void Get_Rank(int x)
{
int u=root;
if(!u) return;
while(e[u].ch[x>e[u].v]&&x!=e[u].v)
u=e[u].ch[x>e[u].v];
Splay(u,0);
}
inline int Get_Val(int x)
{
int u=root;
if(e[u].size<x)
return false;
while(1)
{
int y=e[u].ch[0];
if(x>e[y].size+e[u].recy)
x-=e[y].size+e[u].recy,u=e[u].ch[1];
else
if(e[y].size>=x) u=y;
else
return e[u].v;
}
}
inline int Get_Next(int x,bool op)
{
Get_Rank(x);
int u=root;
if((e[u].v>x&&op)||(e[u].v<x&&!op)) return u;
u=e[u].ch[op];
while(e[u].ch[op^1]) u=e[u].ch[op^1];
return u;
}
inline void Delete(int x)
{
int last=Get_Next(x,0);
int next=Get_Next(x,1);
Splay(last,0);
Splay(next,last);
int del=e[next].ch[0];
if(e[del].recy>1)
e[del].recy--,Splay(del,0);
else
e[next].ch[0]=0;
}
Treap
const int N=1e5+7,INF=0x7fffffff;
struct Treap
{
int val,dat;
int l,r;
int size,cnt;
#define val(x) t[x].val
#define dat(x) t[x].dat
#define l(x) t[x].l
#define r(x) t[x].r
#define size(x) t[x].size
#define cnt(x) t[x].cnt
}t[N];
int n,root,tot;
int New(int val)
{
val(++tot)=val;
dat(tot)=rand();
cnt(tot)=size(tot)=1;
return tot;
}
inline void update(int p)
{
size(p)=size(l(p))+size(r(p))+cnt(p);
}
inline void Build()
{
New(-INF),New(INF);
root=1;
r(root)=2;
update(root);
}
int Get_Rank(int p,int val)
{
if(p==0) return 0;
if(val(p)==val) return size(l(p))+1;
if(val<val(p)) return Get_Rank(l(p),val);
return Get_Rank(r(p),val)+size(l(p))+cnt(p);
}
int Get_Val(int p,int rank)
{
if(p==0) return INF;
if(size(l(p))>=rank) return Get_Val(l(p),rank);
if(size(l(p))+cnt(p)>=rank) return val(p);
return Get_Val(r(p),rank-size(l(p))-cnt(p));
}
inline void zig(int &p)
{
int q=l(p);
l(p)=r(q),r(q)=p;
p=q;
update(r(p)),update(p);
}
inline void zag(int &p)
{
int q=r(p);
r(p)=l(q),l(q)=p;
p=q;
update(l(p)),update(p);
}
void Insert(int &p,int val)
{
if(p==0)
{
p=New(val);
return ;
}
if(val(p)==val)
{
cnt(p)++;
update(p);
return ;
}
if(val<val(p))
{
Insert(l(p),val);
if(dat(l(p))>dat(p))
zig(p);
}
else
{
Insert(r(p),val);
if(dat(r(p))>dat(p))
zag(p);
}
update(p);
}
int Get_Pre(int val)
{
int ans=1;
int p=root;
while(p)
{
if(val(p)==val)
{
if(l(p)>0)
{
p=l(p);
while(r(p)) p=r(p);
ans=p;
}
break;
}
if(val(p)<val&&val(p)>val(ans)) ans=p;
p=val<val(p)?l(p):r(p);
}
return val(ans);
}
int Get_Next(int val)
{
int ans=2;
int p=root;
while(p)
{
if(val(p)==val)
{
if(r(p)>0)
{
p=r(p);
while(l(p)) p=l(p);
ans=p;
}
break;
}
if(val(p)>val&&val(p)<val(ans)) ans=p;
p=val<val(p)?l(p):r(p);
}
return val(ans);
}
void Remove(int &p,int val)
{
if(p==0) return ;
if(val(p)==val)
{
if(cnt(p)>1)
{
cnt(p)--;
update(p);
return ;
}
if(l(p)||r(p))
{
if(r(p)==0||dat(l(p))>dat(r(p)))
zig(p),Remove(r(p),val);
else
zag(p),Remove(l(p),val);
update(p);
}
else
p=0;
return ;
}
val<val(p)?Remove(l(p),val):Remove(r(p),val);
update(p);
}
树剖
const int N=1e5+7;
struct rec{int nxt,to;}e[N<<1];
int fst[N<<1];
int n,m,op;
int w[N];
//w:点权
ll sum[N<<2],lz[N<<2];
int size[N],son[N],fa[N],dep[N];
//size:子树的大小
//son:重儿子
//fa:父节点
//dep:深度
int top[N],rev[N],seg[N<<1];
//top:所在重链的起点
//seg:节点在线段树上的位置 seg[x]=y:x在线段树上的位置为y
//rev:线段树上的位置对应的节点 rev[x]=y:线段树上第x个位置为y节点
int t1=0,t2=0;
//t1为第一次建边时的序,t2为建线段树时的序
void read(int &x)
{
char ch=getchar();x=0;int f=1;
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x*=f;
}
void add(int u,int v)
{
e[++t1].nxt=fst[u];
e[t1].to=v;
fst[u]=t1;
}
//以下为树剖操作
void dfs1(int x,int f)//求出dep,fa,size,son
{
dep[x]=dep[f]+1;
fa[x]=f;
size[x]=1;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==f) continue;
dfs1(y,x);
size[x]+=size[y];
if(size[y]>size[son[x]])
//如果子节点y的大小大于当前重儿子的大小,更新x的重儿子
son[x]=y;
}
}
void dfs2(int u,int f)//求出rev,seg,top
{
if(son[u])
//如果u有重儿子,加入线段树中
//能够保证重链中的节点的dfs2序是连续的
{
int v=son[u];
top[v]=top[u];//更新top,重儿子的top和自身top一定是同一个值
seg[v]=++t2;//v对应线段树上第++t2个位置
rev[t2]=v;//线段树上第t2个位置为v
dfs2(v,u);
}
for(int i=fst[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(!top[v]&&v!=f)//top[v]==0,说明它不在u所在重链中,是个轻儿子
{
top[v]=v;//其所在重链的起点为自身
seg[v]=++t2;
rev[t2]=v;
dfs2(v,u);
}
}
}
//以上为树剖操作
//以下为线段树操作
void build(int k,int l,int r)
{
if(l==r)
{
sum[k]=w[rev[l]];//rev在这儿起到作用
return;
}
int m=(l+r)>>1;
build(k<<1,l,m);
build(k<<1|1,m+1,r);
sum[k]=sum[k<<1]+sum[k<<1|1];
}
void add_v(int k,int l,int r,ll v)
{
lz[k]+=v;
sum[k]+=(ll)(r-l+1)*v;
}
void push_down(int k,int l,int r)
{
if(lz[k])
{
int m=(l+r)>>1;
add_v(k<<1,l,m,lz[k]);
add_v(k<<1|1,m+1,r,lz[k]);
}
lz[k]=0;
}
void change(int k,int l,int r,int x,int y,int v)
{
if(x<=l&&r<=y)
{
add_v(k,l,r,v);
return ;
}
int m=(l+r)>>1;
push_down(k,l,r);
if(m>=x) change(k<<1,l,m,x,y,v);
if(m<y) change(k<<1|1,m+1,r,x,y,v);
sum[k]=sum[k<<1]+sum[k<<1|1];
}
ll query(int k,int l,int r,int x,int y)
{
if(x<=l&&r<=y) return sum[k];
int m=(l+r)>>1;
push_down(k,l,r);
ll rs=0;
if(m>=x) rs=query(k<<1,l,m,x,y);
if(m<y) rs+=query(k<<1|1,m+1,r,x,y);
return rs;
}
//以上为线段树操作
//以下为树剖询问
ll ask(int x,int y)
{
int fx=top[x],fy=top[y];
ll rs=0;
while(fx!=fy)//不在一条重链中
{
if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);//使x为两者中深度更深的一个
rs+=query(1,1,t2,seg[fx],seg[x]);//rs加上x到所在重链顶部的值
x=fa[fx],fx=top[x];//再使x为重链顶的父亲;
}
if(dep[x]>dep[y]) swap(x,y);
rs+=query(1,1,t2,seg[x],seg[y]);//若在一条重链中,因为重链是连续的区间,故直接询问区间值即可
return rs;
}
//以上为树剖询问
void Read()
{
read(n),read(m);
memset(son,0,sizeof(son));
for(int i=1;i<=n;i++)
read(w[i]);
for(int i=1,x,y;i<n;i++)
{
read(x),read(y);
add(x,y),add(y,x);
}
}
void Work()
{
t2=top[1]=rev[1]=seg[1]=1;
dfs1(1,0);
dfs2(1,0);
build(1,1,t2);
}
void Answer()
{
int x,y;
while(m--)
{
read(op),read(x);
if(op==3)
printf("%lld\n",ask(1,x));
else
{
read(y);
if(op==1)
change(1,1,t2,seg[x],seg[x],y);
else
change(1,1,t2,seg[x],seg[x]+size[x]-1,y);
}
}
}
Tarjan
割点
const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=0;
bool cut[N];
int dfn[N],low[N];
int n,m,num=0;
int root;
void add(int u,int v)
{
e[++tot].to=v;
e[tot].nxt=fst[u];
fst[u]=tot;
}
void Tarjan(int x)
{
dfn[x]=low[x]=++num;
int flag=0;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(!dfn[y])
{
Tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
{
flag++;
if(x!=root||flag>1)
cut[x]=true;
}
}
else low[x]=min(low[x],dfn[y]);
}
}
割边
const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=1;
//跟平常书写习惯不同,tot要赋初值为1
bool bridge[N<<1];
int dfn[N],low[N];
int n,m,num=0;
void add(int u,int v)
{
e[++tot].to=v;
e[tot].nxt=fst[u];
fst[u]=tot;
}
void Tarjan(int x,int in_edge)
{
dfn[x]=low[x]=++num;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(!dfn[y])
{
Tarjan(y,i);
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x])
bridge[i]=bridge[i^1]=1;
}
else if(i!=(in_edge^1))
low[x]=min(low[x],dfn[y]);
}
}
e-DCC的缩点
const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
struct recc{int to,nxt;}ec[N<<1];
int fst[N],tot=1;
int fstc[N],totc=1;
bool bridge[N<<1];
int dfn[N],low[N];
int n,m,num=0;
int c[N],dcc;
void add(int u,int v)
{
e[++tot].to=v;
e[tot].nxt=fst[u];
fst[u]=tot;
}
void add_c(int u,int v)
{
e[++totc].to=v;
e[totc].nxt=fstc[u];
fstc[u]=totc;
}
void Tarjan(int x,int in_edge)
{
dfn[x]=low[x]=++num;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(!dfn[y])
{
Tarjan(y,i);
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x])
bridge[i]=bridge[i^1]=1;
}
else if(i!=(in_edge^1))
low[x]=min(low[x],dfn[y]);
}
}
void dfs(int x)
{
c[x]=dcc;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(c[y]||bridge[i]) continue;
dfs(y);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) Tarjan(i,0);
for(int i=1;i<=n;i++)
if(!c[i])
{
++dcc;
dfs(i);
}
for(int i=2;i<=tot;i++)
{
int x=e[i^1].to,y=e[i].to;
if(c[x]==c[y]) continue;
add_c(c[x],c[y]);
}
printf("缩点之后的森林,点数%d,边数%d(可能有重边)\n",dcc,totc/2);
for(int i=2;i<totc;i+=2)
printf("%d %d\n",ec[i^1].to,ec[i].to);
return 0;
}
v-DCC的缩点
const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=0;
bool cut[N];
int dfn[N],low[N];
int n,m,num=0;
int root;
int stac[N],top=0;
vector<int>dcc[N];
int cnt;
int new_id[N];
void add(int u,int v)
{
e[++tot].to=v;
e[tot].nxt=fst[u];
fst[u]=tot;
}
void Tarjan(int x)
{
dfn[x]=low[x]=++num;
stac[++top]=x;
if(x==root&&fst[x]==0)
{
dcc[++cnt].push_back(x);
return ;
}
int flag=0;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(!dfn[y])
{
Tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
{
flag++;
if(x!=root||flag>1)
cut[x]=true;
cnt++;
int z;
do
{
z=stac[top--];
dcc[cnt].push_back(z);
}while(z!=y);
dcc[cnt].push_back(x);
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
if(x==y) continue;
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) root=i,Tarjan(i);
//给每个割点一个新的编号(编号从cnt+1开始)
num=cnt;
for(int i=1;i<=n;i++)
if(cut[i]) new_id[i]=++num;
//建新图,从每个v-DCC到它包含的所有割点连边
tc=1;
for(int i=1;i<=cnt;i++)
for(int j=0;i<dcc[i].size();j++)
{
int x=dcc[i][j];
if(cut[x])
{
add_c(i,new_id[x]);
add_c(new_id[x],i);
}
else c[x]=i;//除割点外,其他点仅属于1个v-DCC
}
/*输出不想写了*/
return 0;
}
边连通分量
const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=1;
bool bridge[N<<1];
int dfn[N],low[N];
int n,m,num=0;
int c[N],dcc;
void add(int u,int v)
{
e[++tot].to=v;
e[tot].nxt=fst[u];
fst[u]=tot;
}
void Tarjan(int x,int in_edge)
{
dfn[x]=low[x]=++num;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(!dfn[y])
{
Tarjan(y,i);
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x])
bridge[i]=bridge[i^1]=1;
}
else if(i!=(in_edge^1))
low[x]=min(low[x],dfn[y]);
}
}
void dfs(int x)
{
c[x]=dcc;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(c[y]||bridge[i]) continue;
dfs(y);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) Tarjan(i,0);
for(int i=1;i<=n;i++)
if(!c[i])
{
++dcc;
dfs(i);
}
printf("There are %d e-DCCs.\n",dcc);
for(int i=1;i<=n;i;++)
printf("%d belongs to DCC %d.\n",i,c[i]);
return 0;
}
点连通分量
const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=0;
bool cut[N];
int dfn[N],low[N];
int n,m,num=0;
int root;
int stac[N],top=0;
vector<int>dcc[N];
int cnt;
void add(int u,int v)
{
e[++tot].to=v;
e[tot].nxt=fst[u];
fst[u]=tot;
}
void Tarjan(int x)
{
dfn[x]=low[x]=++num;
stac[++top]=x;
if(x==root&&fst[x]==0)//孤立的点
{
dcc[++cnt].push_back(x);
return ;
}
int flag=0;
for(int i=fst[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(!dfn[y])
{
Tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
{
flag++;
if(x!=root||flag>1)
cut[x]=true;
cnt++;
int z;
do
{
z=stac[top--];
dcc[cnt].push_back(z);
}while(z!=y);
dcc[cnt].push_back(x);
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
if(x==y) continue;
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) root=i,Tarjan(i);
for(int i=1;i<=cnt;i++)
{
printf("v-DCC #%d:",i);
for(int j=0;j<dcc[i].size();j++)
printf(" %d",dcc[i][j]);
puts("");
}
return 0;
}
二分图(最大匹配匈牙利)
bool check(int x)
{
for(int i=1;i<=b;i++)
if(mp[x][i])
{
if(vis[i])
continue;
vis[i]=1;
if(!marry[i]||check(marry[i]))
{
marry[i]=x;
return true;
}
}
return false;
}
inline int work()
{
int ans=0;
for(int i=1;i<=a;i++)
{
memset(vis,0,sizeof(vis));
if(check(i))
ans++;
}
return ans;
}
圆方树
void Tarjan(int u)
{
dfn[u]=low[u]=++sub,st[++top]=u;
for(int i=fst[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(!dfn[v])
{
Tarjan(v);
low[u]=min(low[v],low[u]);
if(low[v]==dfn[u])
{
w[++cnt]=1;
while(st[top]!=v)
{
w[cnt]++;
add(cnt,st[top],1);
top--;
}
add(cnt,u,1);
top--,w[cnt]++,add(v,cnt,1);
}
}
else
low[u]=min(dfn[v],low[u]);
}
}