打印3
图论
tarjan 缩强连通分量
int dfn[N],low[N],dfscnt;
int stack[N],top;
int scc[N],scccnt;
void tarjan(int u){
dfn[u]=low[u]=++dfscnt;
stack[top++]=u;
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!dfn[v]){
tarjan(v);
low[u]=std::min(low[u],low[v]);
}
else if(!scc[v]) low[u]=std::min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
scccnt++;
do{
scc[stack[--top]]=scccnt;
}while(stack[top]^u);
}
}
tarjan 求割点
int dfn[N],low[N],dfscnt;
int cut[N];
void tarjan(int u,int root){
dfn[u]=low[u]=++dfscnt;
int cnt=0;
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!dfn[v]){
tarjan(v,root);
low[u]=std::min(low[v],low[u]);
if(low[v]>=dfn[u]&&u!=root) cut[u]=1;
cnt++;
}
low[u]=std::min(low[u],dfn[v]);
}
if(cnt>1&&u==root) cut[u]=1;
}
tarjan 求桥
void tarjan(int u){
dfn[u]=low[u]=++dfscnt;
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!dfn[v]){
fa[v]=u;tarjan(v);
low[u]=std::min(low[u],low[v]);
if(low[v]>dfn[u]) bridge[v]=1,ans++;
}
else if(v!=fa[u]) low[u]=std::min(low[u],dfn[v]);
}
}
广义圆方树
void tarjan(int u){
low[u]=dfn[u]=++dfscnt;stack[top++]=u;
for(int v,i=fir[u];i;i=nex[i]){
v=to[i];
if(!dfn[v]){
tarjan(v);
low[u]=std::min(low[u],low[v]);
if(low[v]>=dfn[u]){
bcccnt++;
do{
add_(bcccnt,stack[--top]);add_(stack[top],bcccnt);
bcc[bcccnt].push_back(stack[top]);
}while(stack[top]!=v);
add_(bcccnt,u);add_(u,bcccnt);
bcc[bcccnt].push_back(u);
}
}
else low[u]=std::min(low[u],dfn[v]);
}
}
for(int i=1;i<=n;i++)if(!dfn[i]) tarjan(i),top=0;
仙人掌圆方树
void tarjan(int u,int father){
dfn[u]=low[u]=++dfscnt;stack[top++]=u;
for(reg int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(v==father) continue;
if(!dfn[v]){
sum[v]=sum[u]+G.w[i];
tarjan(v,u);
low[u]=std::min(low[u],low[v]);
if(low[v]>dfn[u]) T.add(u,v,G.w[i]),T.add(v,u,G.w[i]);
}
else if(low[u]>dfn[v]){
low[u]=dfn[v];bcccnt++;
for(reg int j=top-1;stack[j]^v;j--){
T.add(bcccnt,stack[j],w);T.add(stack[j],bcccnt,w);
}
T.add(bcccnt,v,0);T.add(v,bcccnt,0);
}
}
top--;
}
n=bcccnt;
tarjan(1,0);
st 表 \(O(n\log n)-O(1)\) 求 LCA
struct Graph{
int fir[N],nex[M],to[M],tot;
inline void add(int u,int v,int c,int flag=1){
to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;
if(flag) add(v,u,0);
}
int st[20][N*2],log2[N*2];
int dfscnt,dfn[N],id[N*2];
int deep[N];
void dfs(int u,int fa=0){
deep[u]=deep[fa]+1;dfn[u]=++dfscnt;id[dfscnt]=u;
for(int v,i=fir[u];i;i=nex[i]){
v=to[i];
if(v==fa) continue;
sum[v]=sum[u]+w[i];
dfs(v,u);id[++dfscnt]=u;
}
}
inline int getLca(int u,int v){
if(dfn[u]>dfn[v]) lib::swap(u,v);
u=dfn[u];v=dfn[v];
int len=log2[v-u+1];
return deep[st[len][u]]<deep[st[len][v-(1<<len)+1]]?st[len][u]:st[len][v-(1<<len)+1];
}
inline long long getDis(int u,int v){return deep[u]+deep[v]-(deep[getLca(u,v)]<<1);}
inline void init(){
for(int u,v,i=1;i<n;i++) u=read(),v=read(),add(u,v,read());
dfs(1);st[0][1]=id[1];
for(int i=2;i<=dfscnt;i++) log2[i]=log2[i>>1]+1,st[0][i]=id[i];
for(int j=1;j<19;j++)for(int i=1;i+(1<<j)<=dfscnt;i++){
st[j][i]=deep[st[j-1][i]]<deep[st[j-1][i+(1<<(j-1))]]?st[j-1][i]:st[j-1][i+(1<<(j-1))];
}
}
}G;
dinic 最大流
#define Type int
#define _INF _INT_INF
struct Graph{
int fir[N],_fir[N],nex[M],to[M],tot;
Type w[M];
inline void add(int u,int v,Type c,int flag=1){
to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;w[tot]=c;
if(flag) add(v,u,0,0);
}
}G;
int n,S,T;
int deep[N];
int left,right,que[N];
inline int bfs(){
__builtin_memset(deep,0,(n+1)*sizeof deep[0]);
left=right=0;que[0]=S;deep[S]=1;
int u;
while(left<=right){
u=que[left++];
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(deep[v]||!G.w[i]) continue;
deep[v]=deep[u]+1;que[++right]=v;
if(v==T) return 1;
}
}
return 0;
}
Type dfs(int u,Type now=_INF){
if(u==T) return now;
Type res=now;
for(int v,&i=G._fir[u];i;i=G.nex[i]){
v=G.to[i];
if(deep[v]!=deep[u]+1||!G.w[i]) continue;
Type k=dfs(v,lib::min(res,G.w[i]));
if(!k) deep[v]=0;
else G.w[i]-=k,G.w[i^1]+=k,res-=k;
if(!res) break;
}
return now-res;
}
inline Type dinic(){
Type ans=0;
while(bfs()){
Type now;
__builtin_memcpy(G._fir,G.fir,(n+1)*sizeof G.fir[0]);
while(now=dfs(S)) ans+=now;
}
return ans;
}
最小费用最大流
inline void dij(){
std::memset(dis,0x3f,sizeof dis);dis[S]=0;
while(!pque.empty()) pque.pop();
pque.push(std::make_pair(0,S));
reg int u,i,v;
while(!pque.empty()){
u=pque.top().second;
if(dis[u]!=-pque.top().first){pque.pop();continue;}
pque.pop();
if(u==T) break;
for(i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
long long len=G.c[i]+h[u]-h[v];
if(!G.w[i]||dis[v]<=dis[u]+len) continue;
dis[v]=dis[u]+len;
pre_node[v]=u;pre_edge[v]=i;
pque.push(std::make_pair(-dis[v],v));
}
}
}
int in[N],left,right,que[N*20];
inline void spfa(){
left=right=0;que[0]=S;
std::memset(h,0x3f,sizeof h);
h[S]=0;in[S]=1;
reg int u,i,v;
while(left<=right){
u=que[left++];in[u]=0;
for(i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!G.w[i]||h[v]<=h[u]+G.c[i]) continue;
h[v]=h[u]+G.c[i];
if(!in[v]) que[++right]=v,in[v]=1;
}
}
}
long long maxflow,ans;
inline void work(int n){
spfa();
for(;;){
dij();
if(dis[T]==LL_INF) break;
long long minflow=LL_INF;
for(reg int i=T;i^S;i=pre_node[i]) minflow=std::min(minflow,G.w[pre_edge[i]]);
for(reg int i=T;i^S;i=pre_node[i]) G.w[pre_edge[i]]-=minflow,G.w[pre_edge[i]^1]+=minflow;
maxflow+=minflow;ans+=minflow*(dis[T]+h[T]);
for(reg int i=1;i<=n;i++) h[i]=std::min(h[i]+dis[i],LL_INF);
}
}
zkw 费用流(能带有负权):https://artofproblemsolving.com/community/c1368h1020435
int n,m,S,T;
int mincost,maxflow,h[N];
int vis[N];
inline void spfa(){
static int que[M*10],left,right;
__builtin_memset(h,0x3f,sizeof h);
h[S]=0;vis[S]=1;
left=0;right=-1;que[++right]=S;
int u,i,v;
while(left<=right){
u=que[left++];vis[u]=0;
for(i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!G.w[i]||h[v]<=h[u]+G.c[i]) continue;
h[v]=h[u]+G.c[i];
if(!vis[v]) que[++right]=v,vis[v]=1;
}
}
}
int dfs(int u,int want=_INT_INF){
if(u==T) return mincost+=(h[S]-h[T])*want,maxflow+=want,want;
vis[u]=1;
int last=want;
for(int v,&i=G._fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!G.w[i]||vis[v]||G.c[i]!=h[u]-h[v]) continue;
int k=dfs(v,lib::min(last,G.w[i]));
G.w[i]-=k;G.w[i^1]+=k;last-=k;
if(!last) break;
}
return want-last;
}
inline int relable(){
int d=_INT_INF;
for(int i=1;i<=n;i++)if(vis[i])
for(int j=G.fir[i];j;j=G.nex[j])if(G.w[j]&&!vis[G.to[j]]) lib::chkMin(d,G.c[j]-h[i]+h[G.to[j]]);
if(d==_INT_INF) return 0;
for(int i=1;i<=n;i++)if(vis[i]) h[i]+=d;
return 1;
}
inline void zkw(){
spfa();
do{
do{
__builtin_memset(vis,0,sizeof vis);__builtin_memcpy(G._fir,G.fir,sizeof G._fir);
}while(dfs(S));
}while(relable());
}
有源汇上下界最大流
long long d[N];
inline void add(int u,int v,long long l,long long r){
G.add(u,v,r-l);
d[u]-=l;d[v]+=l;
}
int main(){
int s=n+1,t=s+1;
S=t+1;T=S+1;
long long sum=0;
for(int i=1;i<=t;i++){
if(d[i]>0) G.add(S,i,d[i]),sum+=d[i];
else if(d[i]<0) G.add(i,T,-d[i]);
}
G.add(t,s,LL_INF);
if(dinic()^sum) puts("-1\n");
else{
for(int i=G.fir[S];i;i=G.nex[i]) G.w[i]=G.w[i^1]=0;
for(int i=G.fir[T];i;i=G.nex[i]) G.w[i]=G.w[i^1]=0;
sum=G.w[G.tot];G.w[G.tot]=G.w[G.tot-1]=0;
S=s;T=t;
printf("%lld\n\n",sum+dinic());
}
return 0;
}
上下界最小费用可行流
long long ans;
int main(){
int n,m;
n=read();m=read();
int s=1,t=n+1;
S=t+1;T=S+1;G.tot=1;
long long ans=0;
for(int i=1;i<=m;i++){
int u=read(),v=read(),c=read();
d[i]--;d[v]++;ans+=c;
G.add(i,v,LL_INF,c);
}
int sum=0;
for(int i=1;i<=t;i++){
if(d[i]>0) G.add(S,i,d[i],0),sum+=d[i];
else if(d[i]<0) G.add(i,T,-d[i],0);
}
G.add(t,s,LL_INF,0);
work(T);//最小费用最大流
printf("%lld \n",ans+::ans);
return 0;
}
最小割树
Graph G,T;
struct Flow{
int S,T;
int deep[N];
int left,right,que[N];
inline int bfs(){
std::memset(deep,0,sizeof deep);
left=right=0;
que[0]=S;deep[S]=1;
int u;
while(left<=right){
u=que[left++];
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(deep[v]||!G.w[i]) continue;
deep[v]=deep[u]+1;que[++right]=v;
if(v==T) return 1;
}
}
return 0;
}
int dfs(int u,int now=INT_INF){
if(u==T) return now;
int res=now;
for(int v,&i=G.fir_[u];i;i=G.nex[i]){
v=G.to[i];
if(deep[v]!=deep[u]+1||!G.w[i]) continue;
int k=dfs(v,std::min(res,G.w[i]));
if(!k) deep[v]=0;
else G.w[i]-=k,G.w[i^1]+=k,res-=k;
if(!res) break;
}
return now-res;
}
inline void init(){
for(int i=2;i<=G.tot;i+=2){
G.w[i]+=G.w[i^1];
G.w[i^1]=0;
}
}
inline int dinic(int s,int t){
init();S=s;T=t;
int ans=0,now=0;
while(bfs()){
std::memcpy(G.fir_,G.fir,sizeof G.fir);
while(now=dfs(s)) ans+=now;
}
return ans;
}
}F;
int min[11][N],fa[11][N],deep[N];
int node[N],tmp1[N],tmp2[N];
void build(int l,int r){
if(l==r) return;
int s=node[l],t=node[l+1];
int cut=F.dinic(s,t);
T.add(s,t,cut);T.add(t,s,cut);
int cnt1=0,cnt2=0;
for(int i=l;i<=r;i++){
if(F.deep[node[i]]) tmp1[++cnt1]=node[i];
else tmp2[++cnt2]=node[i];
}
for(int i=l;i<l+cnt1;i++) node[i]=tmp1[i-l+1];
for(int i=l+cnt1;i<=r;i++) node[i]=tmp2[i-cnt1-l+1];
build(l,l+cnt1-1);build(l+cnt1,r);
}
Stoer-Wagner 求无向图最小割
int S,T;
int w[N],inA[N];
int del[N],dis[N][N];
inline int mincut(int x){
std::memset(w,0,sizeof w);std::memset(inA,0,sizeof inA);
w[0]=-1;
for(int id,i=1;i<=n-x+1;i++){
id=0;
for(int j=1;j<=n;j++)if(!inA[j]&&!del[j]&&w[j]>w[id]) id=j;
inA[id]=1;
if(i==n-x) S=id;
else if(i==n-x+1) T=id;
for(int j=1;j<=n;j++)if(!inA[j]&&!del[j]) w[j]+=dis[id][j];
}
return w[T];
}
inline int sw(){
int ret=1e9;
for(int i=1;i<n;i++){
ret=std::min(ret,mincut(i));
del[T]=1;
for(int j=1;j<=n;j++) dis[S][j]+=dis[T][j],dis[j][S]+=dis[j][T];
}
return ret;
}
一般图最大匹配
inline int find(int k){return fa[k]==k?k:fa[k]=find(fa[k]);}
inline int getLca(int u,int v){
u=find(u);v=find(v);dfscnt++;
while(dfn[u]^dfscnt){
dfn[u]=dfscnt;
u=find(pre[match[u]]);
if(v) lib::swap(u,v);
}
return u;
}
int que[N],*left,*right;
inline void dealFlower(int u,int v,int root){//u,v are both even vertex
while(find(u)^root){
pre[u]=v;v=match[u];
if(color[v]==2) color[v]=1,*++right=v;
if(find(u)!=root) fa[u]=root;
if(find(v)!=root) fa[v]=root;
u=pre[v];
}
}
inline int bfs(int u){
__builtin_memset(color+1,0,n*sizeof color[0]);__builtin_memset(pre+1,0,n*sizeof pre[0]);
for(int i=1;i<=n;i++) fa[i]=i;
left=que;right=que-1;*++right=u;
color[u]=1;pre[u]=0;
while(left<=right){
u=*left++;
for(int d,v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(color[v]==2||find(u)==find(v)) continue;
if(color[v]) d=getLca(u,v),dealFlower(u,v,d),dealFlower(v,u,d);//flower
else{
color[v]=2;color[match[v]]=1;
if(match[v]) pre[v]=u,*++right=match[v];
else{
while(u) d=match[u],match[u]=v,match[v]=u,u=pre[d],v=d;
return 1;
}
}
}
}
return 0;
}
for(int i=1;i<=n;i++)if(!match[i]) ans+=bfs(i);
tarjan 最小树形图
int uniFa[N];
inline int find(int k){return k==uniFa[k]?k:uniFa[k]=find(uniFa[k]);}
struct Edge{
int u,v,w,w0;
};
struct Node{
Node *ls,*rs,*root;
int deep,tag;
Edge *edge;
inline void pushdown(){
ls->tag+=tag;rs->tag+=tag;
edge->w+=tag;
tag=0;
}
}nullNode,*null=&nullNode;
int tot;
inline void New(Node *&x,Edge *e){
x=new Node;
x->deep=1;x->tag=0;
x->ls=x->rs=null;
x->root=x;x->edge=e;
}
Node *merge(Node *x,Node *y){
if(x==null) return y;
if(y==null) return x;
if(x->edge->w+x->tag>y->edge->w+y->tag) std::swap(x,y);
x->pushdown();
x->rs=merge(x->rs,y);
if(x->ls->deep<x->rs->deep) std::swap(x->ls,x->rs);
x->deep=x->rs->deep+1;
x->ls->root=x->rs->root=x;
return x;
}
inline void pop(Node *&x){
x->pushdown();
Node *ls=x->ls,*rs=x->rs;
delete x;
x=merge(ls,rs);
}
int n,m;
int vis[N],fa[N];
int nex[N];
Edge *in[M],edge[M];
Node *p[N];
inline void contraction(){
for(int i=1;i<=n;i++) p[i]=null,uniFa[i]=i;
for(int i=1;i<=m;i++){
Node *tmp;
New(tmp,&edge[i]);
p[edge[i].v]=merge(p[edge[i].v],tmp);
}
vis[1]=1;
for(int u=1,pre=1,o;p[u];pre=u,vis[u]=1){
do{
in[u]=p[u]->edge;pop(p[u]);
u=find(in[u]->u);
}while(u==pre&&p[u]!=null);
if(u==pre) break;
if(!vis[u]) continue;
p[++n]=null;uniFa[n]=n;
for(pre=u;u^n;){
uniFa[u]=fa[u]=n;
if(p[u]!=null) p[u]->tag-=in[u]->w;
p[n]=merge(p[n],p[u]);
o=find(in[u]->u);
nex[o==n?pre:o]=u;
u=o;
}
}
}
int expand(int,int);
int expand(int u){
int ans=0;
for(int x=nex[u];x^u;x=nex[x]){
if(in[x]->w0==INT_INF) return INT_INF;
if((ans+=in[x]->w0+expand(in[x]->v,x))>=INT_INF) return INT_INF;
}
return ans;
}
inline int expand(int u,int goal){
int ans=0;
for(;u^goal;u=fa[u])
if((ans+=expand(u))>=INT_INF) return INT_INF;
return ans;
}
int main(){
n=read();m=read();int root=read();
for(int i=1;i<=m;i++) edge[i].u=read(),edge[i].v=read(),edge[i].w=edge[i].w0=read();
for(int i=1;i<n;i++) edge[++m]={i,i+1,INT_INF,INT_INF};
edge[++m]={n,1,INT_INF,INT_INF};
contraction();
int ans=expand(root,n);
printf("%d\n",ans==INT_INF?-1:ans);
return 0;
}
点分树
void findRoot(int u,int fa=0){
size[u]=1;maxson[u]=0;
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(v==fa||vis[v]) continue;
findRoot(v,u);size[u]+=size[v];
lib::chkMax(maxson[u],size[v]);
}
lib::chkMax(maxson[u],size[0]-size[u]);
if(maxson[u]<maxson[root]) root=u;
}
int newFa[N];
void divide(int u){
vis[u]=1;
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(vis[v]) continue;
root=0;size[0]=size[v];findRoot(v);findRoot(root);newFa[root]=u;
divide(root);
}
}
inline void build(){
maxson[0]=_INT_INF;size[0]=n;
findRoot(1,n);findRoot(root);divide(root);
}
spfa 找负环
int dis[N],cnt[N];
int left,right,que[N];
inline int spfa(){
std::memset(dis,0x3f,sizeof dis);std::memset(cnt,0,sizeof cnt);
right=left=0;que[0]=1;
dis[1]=0;
int u,v,i;
while(left<=right){
u=que[left++];
for(i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(dis[v]>dis[u]+G.w[i]){
dis[v]=dis[u]+G.w[i];
cnt[v]++;
if(cnt[v]>n) return 1;
que[++right]=v;
}
}
}
return 0;
}
支配树
Graph G,H,T;
int uni[N],min[N];
int dfscnt,dfn[N],id[N],fa[N];
int sdom[N],idom[N];
inline int find(int k){
if(k==uni[k]) return k;
int ret=find(uni[k]);
if(dfn[sdom[min[uni[k]]]]<dfn[sdom[min[k]]]) min[k]=min[uni[k]];
return uni[k]=ret;
}
void dfs(int u){
dfn[u]=++dfscnt;id[dfscnt]=u;
for(int i=G.fir[u];i;i=G.nex[i])
if(!dfn[G.to[i]]) fa[G.to[i]]=u,dfs(G.to[i]);
}
inline void work(int s){
dfs(s);
for(int i=1;i<=n;i++) sdom[i]=uni[i]=min[i]=i;
for(int u,i=dfscnt;i>1;i--){
u=id[i];
for(int v,i=H.fir[u];i;i=H.nex[i]){
v=H.to[i];
if(!dfn[v]) continue;
find(v);
if(dfn[sdom[min[v]]]<dfn[sdom[u]]) sdom[u]=sdom[min[v]];
}
uni[u]=fa[u];
T.add(sdom[u],u);u=fa[u];
for(int v,i=T.fir[u];i;i=T.nex[i]){
v=T.to[i];
find(v);idom[v]=(u==sdom[min[v]])?u:min[v];
}
T.fir[u]=0;
}
for(int u,i=2;i<=dfscnt;i++){
u=id[i];
if(idom[u]^sdom[u]) idom[u]=idom[idom[u]];
}
}
int ans[N];
inline void get_ans(){
for(int i=dfscnt;i>1;i--) ans[idom[id[i]]]+=++ans[id[i]];
ans[id[1]]++;
}
LGV 引理
https://oi-wiki.org//graph/lgv/
匈牙利
int match[N],vis[N];
int dfs(int u){
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(vis[v]) continue;
vis[v]=1;
if(!match[v]||dfs(match[v])) return match[v]=u,match[u]=v,1;
}
return 0;
}
KM
int num_left,num_right;
int G[N][N];
int vis[N],pre[N],match[N],lw[N],d[N];
int que[N],tail,head;
inline int bfs(int u){
tail=head=0;que[0]=u;
pre[u]=0;
while(tail<=head){
u=que[tail++];vis[u]=1;
for(int i=num_left+1;i<=num_right;i++)if(G[u][i]==lw[u]+lw[i]){
if(vis[i]) continue;
vis[i]=1;
if(match[i]) pre[match[i]]=u,que[++head]=match[i];
else{
int d=u,e=i,t;
while(d){
t=match[d];
match[d]=e;match[e]=d;
d=pre[d];e=t;
}
return 1;
}
}
}
return 0;
}
inline long long max_match(){
for(int i=1;i<=num_left;i++){
for(int j=num_left+1;j<=num_right;j++) lw[i]=std::max(lw[i],G[i][j]);
}
for(int i=1;i<=num_left;i++){
std::memset(vis,0,sizeof vis);std::memset(d,0x3f,sizeof d);
if(bfs(i)) continue;
for(int j=1;j<=num_left;j++)if(vis[j])
for(int k=num_left+1;k<=num_right;k++)
if(!vis[k]) d[k]=std::min(d[k],lw[j]+lw[k]-G[j][k]);
while(1){
int now=INT_INF,to,s;
for(int j=num_left+1;j<=num_right;j++)if(!vis[j]) now=std::min(now,d[j]);
for(int j=1;j<=num_left;j++)if(vis[j]) lw[j]-=now;
for(int j=num_left+1;j<=num_right;j++)
if(vis[j]) lw[j]+=now;
else d[j]-=now,to=d[j]?to:j;
if(!match[to]) break;
s=match[to];vis[to]=vis[s]=1;
for(int j=num_left+1;j<=num_right;j++)if(!vis[j]){
d[j]=std::min(d[j],lw[s]+lw[j]-G[s][j]);
}
}
std::memset(vis,0,sizeof vis);
bfs(i);
}
long long ans=0;
for(int i=1;i<=num_right;i++) ans+=lw[i];
return ans;
}
建虚树
inline void buildVT(int n,int *a,Graph &G){
std::sort(a+1,a+1+n,[](const int &p,const int &q){return dfn[p]<dfn[q];});
static int stack[N],top;top=G.tot=0;
stack[++top]=1;
for(int lca,i=1+(a[i]==1);i<=n;i++){
lca=getLca(a[i],stack[top]);
if(lca^stack[top]){
while(dfn[lca]<dfn[stakc[top-1]]) G.add(stack[top-1],stack[top]),top--;
if(lca^stack[top-1]) G.fir[lca]=0,G.add(lca,stack[top]),stack[top]=lca;
else G.add(lca,stack[top--]);
}
G.fir[a[i]]=0;stack[++top]=a[i];
}
while(top--) G.add(stack[top],stack[top+1]);
}
树的最小表示法
struct Center{int a,b;};
int size[N],maxson[N];
void getMaxs(int u,int fa,int n,const Graph &G){
size[u]=1;maxson[u]=0;
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(v==fa) continue;
getMaxs(v,u,n,G);
size[u]+=size[v];maxson[u]=std::max(maxson[u],size[v]);
}
maxson[u]=std::max(maxson[u],n-size[u]);
}
inline Center getCenter(int n,const Graph &G){
getMaxs(1,0,n,G);
int min=1e9;
for(int i=1;i<=n;i++) min=std::min(maxson[i],min);
Center ret={0,0};
for(int i=1;i<=n;i++)if(maxson[i]==min) (ret.a?ret.b:ret.a)=i;
return ret;
}
int fa[N];
std::vector<int>p[N];
int dfs(int u,int deep,const Graph &G){
p[deep].push_back(u);
int ret=deep;
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(v==fa[u]) continue;
fa[v]=u;
ret=std::max(ret,dfs(v,deep+1,G));
}
return ret;
}
int tag[N];
std::vector<int>sonTag[N];
inline void getans(int u,int *ans,const Graph &G){
ans[++ans[0]]=0;
std::vector<int>v;
for(int i=G.fir[u];i;i=G.nex[i])if(G.to[i]^fa[u]) v.push_back(G.to[i]);
std::sort(v.begin(),v.end(),[](const int &a,const int &b){return tag[a]<tag[b];});
for(int j=0,sz=v.size();j<sz;j++) getans(v[j],ans,G);
ans[++ans[0]]=1;
}
inline int ahu(int n,const Graph &G,int root,int *ans){
for(int i=1;i<=n;i++) p[i].clear(),sonTag[i].clear();
fa[root]=0;int h=dfs(root,1,G);
for(int j=0,sz=p[h].size();j<sz;j++) tag[p[h][j]]=0;
int tot=0;
for(int i=h-1;i;i--){
for(int j=0,sz=p[i+1].size(),v;j<sz;j++){
v=p[i+1][j];
sonTag[fa[v]].push_back(tag[v]);
}
std::sort(p[i].begin(),p[i].end(),[](const int &a,const int &b){return sonTag[a]<sonTag[b];});
for(int j=0,sz=p[i].size(),u;j<sz;j++){
u=p[i][j];
if(j&&sonTag[u]!=sonTag[p[i][j-1]]) tot++;
tag[u]=tot;
}
}
getans(root,ans,G);
return h;
}
点分治
int root,sum;
void find(int x,int fa=0){
size[x]=1;max[x]=0;
for(int v,i=G.fir[x];i;i=G.nex[i]){
v=G.to[i];
if(v==fa||vis[v]) continue;
find(v,x);
size[x]+=size[v];
if(max[x]<size[v]) max[x]=size[v];
}
if(max[x]<sum-size[x]) max[x]=n-size[x];
if(max[x]<max[root]) root=x;
}
inline void calc(int u){
}
void divide(int u){
vis[u]=1;
calc(u);
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(vis[v]) continue;
root=0;sum=size[v];
find(v);find(root);
divide(root);
}
}
int main(){
max[0]=INT_INF;sum=n;
find(1);find(root);
divide(root);
return 0;
}