IO
namespace IO{
char buf[1000010],*cur=buf+1000010;
inline char getc(){
(cur==buf+1000010)?fread(cur=buf,1,1000010,stdin):0;
return *cur++;
}
char buff[1000010],*curr=buff;
inline void flush(){
fwrite(buff,1,curr-buff,stdout);
}
inline void putc(const char &ch){
(curr==buff+1000010)?fwrite(curr=buff,1,1000010,stdout):0;
*curr++=ch;
}
inline void rd(int &x){
x=0;char ch=getc();int f=1;
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getc();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getc();
}
x*=f;
}
char st[60];int tp;
void PT(int x){
if(x==0)putc('0');
else{
while(x>0){
st[++tp]=x%10+'0';
x/=10;
}
}
while(tp)putc(st[tp--]);
}
}
using IO::getc;
using IO::putc;
using IO::rd;
using IO::PT;
tarjan
强连通分量
来自这里
void tarjan(int now)
{
dfn[now]=low[now]=++cnt; //初始化
stack[++t]=now; //入栈操作
v[now]=1; //v[]代表该点是否已入栈
for(int i=f[now];i!=-1;i=e[i].next) //邻接表存图
if(!dfn[e[i].v]) //判断该点是否被搜索过
{
tarjan(e[i].v);
low[now]=min(low[now],low[e[i].v]); //回溯时更新low[ ],取最小值
}
else if(v[e[i].v])
low[now]=min(low[now],dfn[e[i].v]); //一旦遇到已入栈的点,就将该点作为连通量的根
//这里用dfn[e[i].v]更新的原因是:这个点可能
//已经在另一个强连通分量中了但暂时尚未出栈,所
//以now不一定能到达low[e[i].v]但一定能到达
//dfn[e[i].v].
if(dfn[now]==low[now])
{
int cur;
do
{
cur=stack[t--];
v[cur]=false; //不要忘记出栈
}while(now!=cur);
}
}
求割点
来自这里
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100009;
struct node {
int to,nxt;
} e[2*maxn];
int n,m,cnt=0,index=0,head[maxn],dfn[maxn],low[maxn],iscut[maxn],ans=0;
void add(int u,int v) {
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void tarjan(int u,int fa) {
int child=0;
dfn[u]=low[u]=++index;
// cout<<"dfs "<<dfn[u]<<" "<<low[u]<<endl;
for(int i=head[u]; i>0; i=e[i].nxt) {
int v=e[i].to;
if(!dfn[v]) {
child++;
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(fa>0&&low[v]>=dfn[u]) {
if(!iscut[u])++ans;//一个顶点可能被标记多次
iscut[u]=1;
// cout<<"df u"<<u<<" ans"<<ans<<endl;
}
} else if(dfn[v]<dfn[u]&&v!=fa)
low[u]=min(low[u],dfn[v]);
}
//cout<<u<<" child "<<child<<endl;
if(fa<0&&child>1) {
//if(!iscut[u])
++ans;//根节点不可能被统计多次
iscut[u]=1;
// cout<<"fa "<<u<<endl;
}
}
int main() {
cin>>n>>m;
int u,v;
for(int i=1; i<=m; i++) {
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
for(int i=1; i<=n; i++)
if(!dfn[i])tarjan(i,-1);
printf("%d\n",ans);
for(int i=1; i<=n; i++)
if(iscut[i])cout<<i<<" ";
}
求割边
来自这里
void Tarjan(int u,int fa)
{
dfn[u] = low[u] = ++indx;
stk.push(u);
int flg = 0;
for(int i=0; i<vt[u].size(); ++i)
{
int v = vt[u][i];
if(!flg && v == fa)
{
flg = 1;
continue;
}
if(!dfn[v])
{
Tarjan(v,u);
low[u] = min(low[u],low[v]);
//if(low[v]>dfn[u])the edge cut
}
else
low[u] = min(low[u],dfn[v]);
}
if(low[u] == dfn[u])
{
num++;
int v;
do
{
v = stk.top();
stk.pop();
belong[v] = num;
}while(u != v);
}
}
点双
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
#define Maxn 1000010
int head[Maxn],v[Maxn<<1],nxt[Maxn<<1],tot=0;
inline int id(int i){
if(i&1)i++;
return i/2;
}
inline void add_edge(int s,int e){
tot++;v[tot]=e;nxt[tot]=head[s];head[s]=tot;
tot++;v[tot]=s;nxt[tot]=head[e];head[e]=tot;
}
int scc[Maxn],cnt;
bool ans[Maxn];
int stack[Maxn],top;
int dfn[Maxn],low[Maxn],dfk;
int hd[Maxn],to[Maxn],la[Maxn],out[Maxn],len=0;
int seq[Maxn];
inline void link(int s,int e){
len++;to[len]=e;la[len]=hd[s];hd[s]=len;
}
void tarjan(int u,int f){
dfn[u]=low[u]=++dfk;
for(int i=head[u];i;i=nxt[i])
if(v[i]!=f){
if(!dfn[v[i]]){
stack[++top]=i;
tarjan(v[i],u);
low[u]=min(low[u],low[v[i]]);
if(low[v[i]]>=dfn[u]){
int pre=top;
int s,e,H=0,res=0;
cnt++;
do{
e=v[stack[top]];
if(stack[top]&1)s=v[stack[top]+1];
else s=v[stack[top]-1];
res++;
seq[res]=stack[top];
if(scc[s]!=cnt){
scc[s]=cnt;
H++;
if(s!=u){
for(int j=hd[s];j;j=la[j])
seq[++res]=to[j];
}
}
if(scc[e]!=cnt){
scc[e]=cnt;
H++;
if(e!=u){
for(int j=hd[e];j;j=la[j])
seq[++res]=to[j];
}
}
top--;
}while(s!=u||e!=v[i]);
if(res==H)
for(int j=1;j<=res;++j)ans[id(seq[j])]=true;
}
}else{
low[u]=min(low[u],dfn[v[i]]);
if(dfn[v[i]]<dfn[u]){
link(u,i);
out[u]++;
}
}
}
}
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
rd(n);rd(m);
int s,e;
for(register int i=1;i<=m;++i){
rd(s);rd(e);
add_edge(s,e);
}
tarjan(1,0);
int Ans=0;
for(register int i=1;i<=m;++i)
if(ans[i])Ans^=i;
printf("%d\n",Ans);
return 0;
}/*
4 4
1 2
2 4
4 3
3 2
*/
点双之间的交点是割点
一些相关结论
AC自动机
void Build_AC(){
tree[root].fail=0;
Q.push(root);
int to;
while(!Q.empty()){
int k=Q.front();
Q.pop();
for(int i=0;i<26;++i){
if(k==root)to=root;
else to=tree[tree[k].fail].son[i];
if(tree[k].son[i]){
tree[tree[k].son[i]].fail=to;
Q.push(tree[k].son[i]);
}else tree[k].son[i]=to;
}
}
}
###
LCT
void push_down(int u){
int ls=tree[u].son[0],rs=tree[u].son[1];
if(tree[u].rev){
tree[ls].rev^=1;
tree[rs].rev^=1;
swap(tree[u].son[0],tree[u].son[1]);
tree[u].rev=0;
}
int num1=tree[u].md,num2=tree[u].ad;
if(num1!=1||num2!=0){
calc(ls,num1,num2);
calc(rs,num1,num2);
tree[u].md=1;tree[u].ad=0;
}
}
void rot(int u){
int f=tree[u].fa,ff=tree[f].fa;
int dir1=who(u),dir2=dir1^1;
if(!rt(f))tree[ff].son[who(f)]=u;
tree[u].fa=ff;
tree[f].son[dir1]=tree[u].son[dir2];
tree[tree[u].son[dir2]].fa=f;
tree[u].son[dir2]=f;
tree[f].fa=u;
push_up(f);
push_up(u);
}
void Splay(int u){
st.push(u);
for(int x=u;!rt(x);x=tree[x].fa)st.push(tree[x].fa);
while(!st.empty()){push_down(st.top());st.pop();}
for(int fa;!rt(u);rot(u)){
if(!rt(fa=tree[u].fa)){
rot((who(u)==who(fa))?fa:u);
}
}
}
void access(int u){
for(int t=0;u;t=u,u=tree[u].fa){
Splay(u);
tree[u].son[1]=t;
push_up(u);
}
}
void makeroot(int u){
access(u);
Splay(u);
tree[u].rev^=1;
}
void link(int s,int e){
makeroot(s);
tree[s].fa=e;
}
void cut(int s,int e){
makeroot(s);
access(e);
Splay(e);
tree[e].son[0]=tree[s].fa=0;
push_up(e);
}
void spilt(int s,int e){
makeroot(e);
access(s);
Splay(s);
}
转载自GXZ的博客
事实上,我们注意到,对于Splay Tree的所有基本操作,除了access和link以外,都不会对虚儿子的信息进行修改。
access操作中割断了实边c[1][x],该边变为了虚边,所以应该加到x的虚儿子信息中,加入了实边t,该边不再是虚边,所以应从x的虚儿子信息中减去。
link操作中为了在加入x时同时更新y的信息,需要makeroot(x),makeroot(y),然后连x->y的虚边(实际上只需要access(y)和splay(y))。
其余的操作,和普通的LCT没有任何区别。
SJ定理
(1)SG==0,有某单一游戏的SG>1。
(2)SG!=0,有某单一游戏的SG>1。(必胜SJ)
(3)SG==0,无某单一游戏的SG>1。(必胜SJ)
(4)SG!=0,无某单一游戏的SG>1。
prufer序列
对于n个点的标号无根树,其方案数为
(
n
−
2
)
!
∏
(
d
i
−
1
)
!
\frac{(n-2)!}{\prod (d_i-1)!}
∏(di−1)!(n−2)!
BM
namespace BM{
int fail[N<<1],dt[N<<1],cur=0,a[N<<1],cnt=0,Bst=0;
poly f[2],bst;
void ins(int n){
dt[n]=a[n];
for(int i=1;i<f[cur].size();++i)dt[n]=(dt[n]-1ll*a[n-i]*f[cur][i]%Mod+Mod)%Mod;
if(!dt[n])return;
fail[cnt++]=n;
cur^=1;
if(cnt==1){
f[cur].resize(n+1,0);
return;
}
int t=1ll*dt[n]*Fast_Pow(dt[fail[Bst]],Mod-2)%Mod;
f[cur].resize(0);f[cur].resize(n-fail[Bst]);f[cur].push_back(t);
if(t)t=Mod-t;
for(int i=1;i<bst.size();++i)f[cur].push_back(1ll*bst[i]*t%Mod);
if(f[cur].size()>=f[cur^1].size())Bst=cnt-1,bst=f[cur^1];
f[cur]+=f[cur^1];
}
inline poly solve(int *_a,int n){
cur=0;cnt=0;Bst=0;bst.resize(0);f[0].resize(0);f[1].resize(0);
for(int i=1;i<=n;++i)a[i]=_a[i],ins(i);
return f[cur];
}
}
回文自动机
namespace PAM{
int ed[Maxn];
int ch[Maxn][26],fail[Maxn],len[Maxn],fa[Maxn];
int last,tot,l;
char s[Maxn];
void init(){
last=0;tot=1;l=0;ed[0]=0;
memset(ch[0],0,sizeof(ch[0]));
memset(ch[1],0,sizeof(ch[1]));
fail[0]=1;
len[1]=-1;
s[0]=-1;
fa[0]=fa[1]=0;
cnt=0;root[0]=root[1]=0;
}
int getfail(int x){
while(s[l-len[x]-1]!=s[l])x=fail[x];
return x;
}
void Add(char c){
l++;
s[l]=c;
int dir=c-'a';
int tmp=getfail(last);
if(!ch[tmp][dir]){
tot++;
memset(ch[tot],0,sizeof(ch[tot]));
len[tot]=len[tmp]+2;
fa[tot]=tmp;
fail[tot]=ch[getfail(fail[tmp])][dir];
Insert(root[tot],root[fail[tot]],1,N,len[tot]);
ch[tmp][dir]=tot;
}
last=ch[tmp][dir];
ed[l]=last;
}
}
稳定婚姻匹配问题
第一轮,每个男人都选择自己名单上排在首位的女人,并向她表白。这种时候会出现两种情况:
(1)该女士还没有被男生追求过,则该女士接受该男生的请求。
(2)若该女生已经接受过其他男生的追求,那么该女生会将该男士与她的现任男友进行比较,若更
喜欢她的男友,那么拒绝这个人的追求,否则,抛弃其男友
证明&&相关材料
void GaleShapley(const int (&man)[N][N],const int (&woman)[N][N],int (&match)[N]){
int wm[N][N]; // wm[i][j]: rank from girl i to boy j
int choose[N]; // choose[i]: current boyfriend of girl i
int manIndex[N]; // manIndex[i]: how many girls that have rejected boy i
int i,j;
int w,m;
for(i=0;i<N;i++){
match[i]=-1;
choose[i]=-1;
manIndex[i]=0;
for(j=0;j<N;j++)
wm[i][woman[i][j]]=j;
}
bool bSingle=false;
while(!bSingle){
bSingle=true;
for(i=0;i<N;i++){
if(match[i]!=-1) // boy i already have a girlfriend
continue;
bSingle=false;
j=manIndex[i]++; // the jth girl that boy i like most
w=man[i][j];
m=choose[w]; // current girl w's boyfriend
if(m==-1 || wm[w][i]<wm[w][m]){ // if girl w prefer boy i
match[i]=w;
choose[w]=i;
if(m!=-1)
match[m]=-1;
}
}
}
}
三角恒等式
cos(α+β)=cosα·cosβ-sinα·sinβ
cos(α-β)=cosα·cosβ+sinα·sinβ
sin(α±β)=sinα·cosβ±cosα·sinβ
tan(α+β)=(tanα+tanβ)/(1-tanα·tanβ)
tan(α-β)=(tanα-tanβ)/(1+tanα·tanβ)
最大流
这里是实现最大闭合权子图
namespace Graph{
int d[1005],head[1005],cur[1005],v[10005],nxt[10005],w[10005],tot=0;
int Q[1005],hd,tl,S,T;
void init_test(){memset(d,-1,sizeof(d));}
void init_graph(){
for(int i=1;i<=tot;++i)head[v[i]]=0;
tot=0;
}
bool Bfs(){
for(int i=0;i<tl;++i)d[Q[i]]=-1;
hd=tl=0;
Q[tl++]=S;d[S]=0;
while(hd<tl){
int u=Q[hd];hd++;
for(int i=head[u];i;i=nxt[i])
if(w[i]&&d[v[i]]<0){
d[v[i]]=d[u]+1;
Q[tl++]=v[i];
if(v[i]==T)return true;
}
}
return false;
}
int find(int u,int flow){
if(u==T||!flow)return flow;
int res=0,minv;
for(int &i=head[u];i;i=nxt[i])
if(w[i]&&d[v[i]]==d[u]+1&&(minv=find(v[i],min(flow,w[i])))){
w[i]-=minv;
if(i&1)w[i+1]+=minv;
else w[i-1]+=minv;
res+=minv;
flow-=minv;
if(!flow)break;
}
return res;
}
void add_edge(int s,int e,int t){
tot++;v[tot]=e;w[tot]=t;nxt[tot]=head[s];head[s]=tot;
tot++;v[tot]=s;w[tot]=0;nxt[tot]=head[e];head[e]=tot;
}
int max_flow(){
int res=0;
memcpy(cur,head,sizeof(int)*(T+1));
while(Bfs()){
res+=find(S,inf);
memcpy(head,cur,sizeof(int)*(T+1));
}
return res;
}
int calc(){
S=n+1;T=n+2;int res=0;
for(int i=1;i<=n;++i)
if(a[i]>=0){
add_edge(S,i,a[i]);
res+=a[i];
}else add_edge(i,T,-a[i]);
res-=max_flow();
return res;
}
}
单调区间,可合并
对于一类可合并的单调区间询问问题
可以维护两个栈st1,st2
st2存着当前的答案,加入好处理
st1存着每个后缀的答案,删除好处理
每次合并好st1的后缀和st2的答案
st1空了就把st2的元素移到st1去,st2变空
费用流三大写法
EK,ZKW,原始对偶
#include<bits/stdc++.h>
using namespace std;
const int inf=1000000000;
int n,m,S,T;
#define Maxn 5005
#define E 100010
#define cout cerr
int maxf=0,Ans=0;
int head[Maxn],cap[E],v[E],w[E],nxt[E],tot=0;
inline void add_edge(int s,int e,int c,int t){
tot++;v[tot]=e;cap[tot]=c;w[tot]=t;nxt[tot]=head[s];head[s]=tot;
tot++;v[tot]=s;cap[tot]=0;w[tot]=-t;nxt[tot]=head[e];head[e]=tot;
}
namespace EK{
int Q[E],hd,tl;
int dis[Maxn];
int inq[Maxn],inqT=0,vis[Maxn],visT=0;
int FR[Maxn];
bool SPFA(){
hd=tl=0;
inqT++;
for(int i=1;i<=n;++i)dis[i]=inf;
dis[S]=0;Q[tl++]=S;inq[S]=inqT;
while(hd<tl){
int u=Q[hd];
hd++;
inq[u]=0;
for(int i=head[u];i;i=nxt[i])
if(cap[i]&&dis[u]+w[i]<dis[v[i]]){
FR[v[i]]=i;
dis[v[i]]=dis[u]+w[i];
if(inq[v[i]]!=inqT){
inq[v[i]]=inqT;
Q[tl++]=v[i];
}
}
}
return dis[T]!=inf;
}
int search(int u,int flow){
if(u==T||!flow){
maxf+=flow;
return flow;
}
vis[u]=visT;
int res=0;
for(int i=head[u];i&&flow;i=nxt[i])
if(cap[i]&&dis[u]+w[i]==dis[v[i]]&&vis[v[i]]!=visT){
int t=search(v[i],min(flow,cap[i]));
Ans+=t*w[i];
cap[i]-=t;
if(i&1)cap[i+1]+=t;
else cap[i-1]+=t;
res+=t;
flow-=t;
}
return res;
}
void solve(){
while(SPFA()){
/*int u=T;int mn=inf;
while(u!=S){
int t=FR[u];
mn=min(mn,cap[t]);
if(t&1)u=v[t+1];
else u=v[t-1];
}
maxf+=mn;
u=T;
while(u!=S){
int t=FR[u];
cap[t]-=mn;
Ans+=mn*w[t];
if(t&1){
cap[t+1]+=mn;
u=v[t+1];
}else{
cap[t-1]+=mn;
u=v[t-1];
}
}*/
visT++;
search(S,inf);
}
}
}
namespace zkw{
//边权为负记得跑一遍SPFA
int dis[Maxn],vis[Maxn],visT=0;
bool flag;
int aug(int u,int flow){
if(u==T){flag=true;maxf+=flow;Ans-=flow*dis[S];return flow;}
vis[u]=visT;
int res=0;
for(int i=head[u];i&&flow;i=nxt[i])
if(cap[i]&&dis[v[i]]==dis[u]+w[i]&&vis[v[i]]!=visT){
int t=aug(v[i],min(flow,cap[i]));
cap[i]-=t;
if(i&1)cap[i+1]+=t;
else cap[i-1]+=t;
res+=t;
flow-=t;
}
return res;
}
bool mdf(){
if(vis[T]==visT)return true;
int mn=inf;
for(int u=1;u<=n;++u)
if(vis[u]==visT)
for(int i=head[u];i;i=nxt[i])
if(vis[v[i]]!=visT&&cap[i])mn=min(mn,dis[u]-dis[v[i]]+w[i]);
if(mn==inf)return false;
for(int i=1;i<=n;++i)
if(vis[i]==visT)dis[i]-=mn;
return true;
}
void solve(){
memset(dis,0,sizeof(int)*(n+1));
do{
visT++;
flag=false;
aug(S,inf);
if(flag)vis[T]=visT;
}while(mdf());
}
}
namespace PD{
///边权为负记得跑一遍SPFA
int D[Maxn],dis[Maxn];
int vis[Maxn],visT;
struct HeapNode{
int u,d;
HeapNode(){u=d=0;}
HeapNode(int _u,int _d){u=_u;d=_d;}
bool operator <(const HeapNode &t)const{return d>t.d;}
};
priority_queue<HeapNode> Q;
bool Dij(){
for(int i=1;i<=n;++i)dis[i]=inf;
while(!Q.empty())Q.pop();
dis[S]=0;Q.push(HeapNode(S,0));
while(!Q.empty()){
HeapNode node=Q.top();
Q.pop();
int u=node.u;
if(dis[u]!=node.d)continue;
for(int i=head[u];i;i=nxt[i])
if(cap[i]&&dis[u]+D[u]+w[i]-D[v[i]]<dis[v[i]]){
dis[v[i]]=dis[u]+D[u]+w[i]-D[v[i]];
Q.push(HeapNode(v[i],dis[v[i]]));
}
}
return dis[T]!=inf;
}
int aug(int u,int flow){
if(u==T||!flow){maxf+=flow;return flow;}
vis[u]=visT;
int res=0;
for(int i=head[u];i;i=nxt[i])
if(cap[i]&&dis[v[i]]==dis[u]+D[u]+w[i]-D[v[i]]&&vis[v[i]]!=visT){
int t=aug(v[i],min(flow,cap[i]));
Ans+=t*w[i];
cap[i]-=t;
if(i&1)cap[i+1]+=t;
else cap[i-1]+=t;
res+=t;
flow-=t;
}
return res;
}
void solve(){
memset(D,0,sizeof(int)*(n+1));
while(Dij()){
visT++;
aug(S,inf);
for(int i=1;i<=n;++i)
if(dis[i]==inf)D[i]=inf;
else D[i]+=dis[i];
}
}
}
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
rd(n);rd(m);rd(S);rd(T);
int s,e,c,t;
for(int i=1;i<=m;++i){
rd(s);rd(e);rd(c);rd(t);
add_edge(s,e,c,t);
}
PD::solve();
printf("%d %d\n",maxf,Ans);
return 0;
}
半平面交
bool check(Line L,Line a,Line b){
Point cro=getcro(a,b);
return cross(L.T-L.S,cro-L.S)<-eps;
}
int cnt;
bool Half(){
head=tail=0;
for (int i = 0; i < cnt; i++) {
while(tail - head > 1&&check(tmp[i], que[tail - 1], que[tail - 2])) tail--;
while(tail - head > 1&&check(tmp[i], que[head], que[head + 1])) head++;
que[tail++] = tmp[i];
}
while(tail - head > 1 && check(que[head], que[tail - 1], que[tail - 2])) tail--;
while(tail - head > 1 && check(que[tail - 1], que[head], que[head + 1])) head++;
if (tail - head < 3) return false;
return true;
}
tutte矩阵
struct Data{
int pre,nxt;
}row[Maxn];
bool b[Maxn];
void del(int x){
b[x]=true;
row[row[x].pre].nxt=row[x].nxt;
row[row[x].nxt].pre=row[x].pre;
}
bool edge[Maxn][Maxn];
int A[Maxn][Maxn],c[Maxn],d[Maxn];
int num[Maxn][Maxn],lis[Maxn];
int mate[Maxn];
void mv1(){rep(i,1,n)rep(j,1,n)A[i][j]=num[i][j];}
int getrank(){
int cnt=0;
rep(i,1,n)rep(j,1,n)A[i][j]=0;
rep(i,1,n){
memcpy(c+1,num[i]+1,sizeof(int)*n);
rep(j,1,n)
if(c[j]){
if(!A[j][j]){
rep(k,j,n)A[j][k]=c[k];
d[j]=Fast_Pow(c[j],Mod-2);
cnt++;lis[cnt]=i;
break;
}
int t=mul(c[j],d[j]);
rep(k,j,n)c[k]=dec(c[k],mul(t,A[j][k]));
}
}
return cnt;
}
void getinv(){
rep(i,1,n)rep(j,1,n)if(i==j)A[i][j]=1;else A[i][j]=0;
rep(i,1,n){
if(!num[i][i]){
rep(j,i+1,n)
if(num[j][i]){
rep(k,i,n)swap(num[i][k],num[j][k]),swap(A[i][k],A[j][k]);
rep(k,1,i-1)swap(A[i][k],A[j][k]);
break;
}
}
int t=Fast_Pow(num[i][i],Mod-2);
rep(j,i+1,n)
if(num[j][i]){
int de=mul(num[j][i],t);
rep(k,i,n){
num[j][k]=dec(num[j][k],mul(num[i][k],de));
A[j][k]=dec(A[j][k],mul(A[i][k],de));
}
rep(k,1,i-1)A[j][k]=dec(A[j][k],mul(A[i][k],de));
}
}
per(i,n,1){
rep(j,i+1,n)
if(num[i][j]){
rep(k,1,n)A[i][k]=dec(A[i][k],mul(A[j][k],num[i][j]));
}
int t=Fast_Pow(num[i][i],Mod-2);
rep(j,1,n)A[i][j]=mul(A[i][j],t);
}
}
void elim(int x,int y){
int t=Fast_Pow(A[x][y],Mod-2);
for(int i=row[0].nxt;i<=n;i=row[i].nxt){
int cur=mul(A[i][y],t);
for(int j=row[0].nxt;j<=n;j=row[j].nxt)
A[i][j]=dec(A[i][j],mul(A[x][j],cur));
}
}
inline void rd(int &x){
x=0;char ch=getchar();int f=1;
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
int main(){
rd(n);rd(m);N=n;
int s,e;
for(int i=1;i<=m;++i){
rd(s);rd(e);
if(s>e)swap(s,e);
int t=mt_rand()%Mod;
num[s][e]=t;
num[e][s]=dec(0,t);
edge[s][e]=edge[e][s]=true;
}
N=getrank();mv1();swap(n,N);
printf("%d\n",n/2);
rep(i,0,n+1){
row[i].pre=i-1;row[i].nxt=i+1;
}
rep(i,1,n)rep(j,1,n)num[i][j]=A[lis[i]][lis[j]];
getinv();
rep(i,1,n)
if(!b[i]){
rep(j,i+1,n)
if(edge[lis[i]][lis[j]]&&A[i][j]&&!b[j]){
mate[lis[i]]=lis[j];mate[lis[j]]=lis[i];
del(i);del(j);
elim(i,j);elim(j,i);
break;
}
}
rep(i,1,N)printf("%d ",mate[i]);puts("");
return 0;
}
支配树
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,m;
#define V 50010
#define E 100010
int rt;
int head[V],v[E],nxt[E],tot=0;
inline void add_edge(int s,int e){tot++;v[tot]=e;nxt[tot]=head[s];head[s]=tot;}
int dfk=0;
int sdom[V],seq[V],label[V],fa[V],anc[V],idom[V];
vector<int> G[V],bucket[V];
void dfs(int u){
sdom[u]=++dfk;
seq[dfk]=u;
label[u]=u;
for(int i=head[u];i;i=nxt[i]){
if(!sdom[v[i]]){
dfs(v[i]);
fa[v[i]]=u;
}
G[v[i]].push_back(u);
}
}
inline void compress(int u){
if(anc[anc[u]]){
compress(anc[u]);
if(sdom[label[anc[u]]]<sdom[label[u]])label[u]=label[anc[u]];
anc[u]=anc[anc[u]];
}
}
inline int eval(int u){
if(anc[u]){
compress(u);
return label[u];
}
return u;
}
inline void link(int p,int u){anc[u]=p;}
ll ans[V];
inline void solve(){
dfs(rt);
for(int i=dfk;i>=2;--i){
int u=seq[i];
for(int j=0;j<G[u].size();++j)sdom[u]=min(sdom[u],sdom[eval(G[u][j])]);
int t=fa[u];
link(t,u);
bucket[seq[sdom[u]]].push_back(u);
for(int j=0;j<bucket[t].size();++j){
int to=bucket[t][j];
int w=eval(to);
idom[to]=sdom[w]<sdom[to]?w:t;
}
bucket[t].clear();
}
ans[rt]=rt;idom[rt]=rt;
for(int i=2;i<=dfk;++i){
int u=seq[i];
if(idom[u]!=seq[sdom[u]])idom[u]=idom[idom[u]];
ans[u]=ans[idom[u]]+u;
}
}
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
tot=0;memset(head,0,sizeof(int)*(n+1));rt=n;
memset(anc,0,sizeof(int)*(n+1));dfk=0;
memset(sdom,0,sizeof(int)*(n+1));
memset(ans,0ll,sizeof(ll)*(n+1));
for(int i=1;i<=n;++i){
bucket[i].clear();
G[i].clear();
}
int s,e;
for(int i=1;i<=m;++i){
rd(s);rd(e);
add_edge(s,e);
}
solve();
for(int i=1;i<n;++i)printf("%lld ",ans[i]);
printf("%lld\n",ans[n]);
}
return 0;
}
带花树
int mate[Maxn],link[Maxn],vis[Maxn],fa[Maxn];
int getroot(int x){
if(fa[x]!=x)fa[x]=getroot(fa[x]);
return fa[x];
}
int ss[Maxn],T;
int Lca(int a,int b){
T++;
while(ss[a]^T){
if(a){ss[a]=T;a=getroot(link[mate[a]]);}
swap(a,b);
}
return a;
}
int Q[Maxn<<1],hd,tl;
void Flower(int x,int y,int p){
while(getroot(x)!=p){
link[x]=y;
fa[y=mate[x]]=fa[x]=p;
if(vis[y]==1)vis[Q[tl++]=y]=2;
x=link[y];
}
}
bool Match(int x){
hd=tl=0;
for(int i=1;i<=n;++i)vis[fa[i]=i]=0;
Q[tl++]=x;vis[x]=2;
while(hd<tl){
int u=Q[hd];hd++;
for(int i=head[u];i;i=nxt[i])
if(!vis[v[i]]){
vis[v[i]]=1;
link[v[i]]=u;
if(!mate[v[i]]){
int node=v[i];
while(node){
u=mate[link[node]];
mate[mate[node]=link[node]]=node;
node=u;
}
return true;
}else vis[Q[tl++]=mate[v[i]]]=2;
}else if(vis[v[i]]==2&&getroot(u)!=getroot(v[i])){
int p=Lca(u,v[i]);
Flower(u,v[i],p);
Flower(v[i],u,p);
}
}
return false;
}
Poly
#define rez resize
const int Mod=998244353;
const int I2=499122177;
typedef vector<int> poly;
namespace modular{
int add(int a,int b){return a+b>=Mod?a+b-Mod:a+b;}
int dec(int a,int b){return a-b<0?a-b+Mod:a-b;}
int mul(int a,int b){return 1ll*a*b%Mod;}
inline int Fast_Pow(int a,int b){
int res=1;
while(b){
if(b&1)res=1ll*res*a%Mod;
a=1ll*a*a%Mod;
b>>=1;
}
return res;
}
}using namespace modular;
namespace QR{
int w;
struct Data{
int a,b;
Data(){a=b=0;}
Data(int _a,int _b){a=_a;b=_b;}
friend Data operator *(Data t1,Data t2){return Data((1ll*t1.a*t2.a+1ll*t1.b*t2.b%Mod*w)%Mod,(1ll*t1.a*t2.b+1ll*t1.b*t2.a)%Mod);}
};
int calc(int x){
if(!x)return x;
int tmp=Fast_Pow(x,(Mod-1)>>1);
if(tmp==Mod-1)return -1;
int a;
while(true){
a=1ll*rand()*rand()%Mod;
w=((1ll*a*a-x)%Mod+Mod)%Mod;
if(Fast_Pow(w,(Mod-1)>>1)==Mod-1)break;
}
Data res=Data(1,0),H=Data(a,1);
tmp=(Mod+1)>>1;
while(tmp){
if(tmp&1)res=res*H;
H=H*H;
tmp>>=1;
}
return min(res.a,Mod-res.a);
}
}
namespace Poly{
int invv[24],len,bit,inv[1<<20|5];
vector<int> rev[24],w[24];
inline void init_w(int lm=1<<18){
w[17].rez(1<<17);w[17][0]=1;w[17][1]=Fast_Pow(3,(Mod-1)/lm);
for(int i=2;i<lm/2;++i)
w[17][i]=1ll*w[17][i-1]*w[17][1]%Mod;
for(int i=16;i>=0;--i){
w[i].rez(1<<i);
for(int j=0;j<(1<<i);++j)w[i][j]=w[i+1][j<<1];
}
inv[0]=inv[1]=1;
for(int i=2;i<=lm;++i)inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
}
void init_r(int up){
len=1;bit=0;
while(len<up)len<<=1,bit++;
if(invv[bit])return;
rev[bit].rez(len);
for(int i=0;i<len;++i)rev[bit][i]=(rev[bit][i>>1]>>1)|((i&1)<<(bit-1));
invv[bit]=inv[len];
}
inline poly operator +(poly a,poly b){
int n=b.size();
if(a.size()<n)a.rez(n);
for(int i=0;i<n;++i)a[i]=add(a[i],b[i]);
return a;
}
inline poly poly_add(poly a,poly b){
int n=b.size();
if(a.size()<n)a.rez(n);
for(int i=0;i<n;++i)a[i]=add(a[i],b[i]);
return a;
}
inline poly operator -(poly a,poly b){
int n=b.size();
if(a.size()<n)a.rez(n);
for(int i=0;i<n;++i)a[i]=dec(a[i],b[i]);
return a;
}
inline poly poly_dec(poly a,poly b){
int n=b.size();
if(a.size()<n)a.rez(n);
for(int i=0;i<n;++i)a[i]=dec(a[i],b[i]);
return a;
}
void NTT(poly &A,int type){
for(int i=0;i<len;++i)
if(i<rev[bit][i])swap(A[i],A[rev[bit][i]]);
for(int i=1,t=0;i<len;i<<=1,++t)
for(int j=0;j<len;j+=i<<1)
for(int k=0;k<i;++k){
int x=A[j+k];
int y=1ll*w[t][k]*A[j+k+i]%Mod;
A[j+k]=add(x,y);
A[j+k+i]=dec(x,y);
}
if(type==1)return;
reverse(++A.begin(),A.end());
for(int i=0;i<len;++i)A[i]=1ll*A[i]*invv[bit]%Mod;
}
poly operator *(poly a,poly b){
int n=a.size(),m=b.size(),t=n+m-1;
if(n<=30||m<=30){
poly c(t);
for(int i=0;i<n;++i)
if(a[i])
for(int j=0;j<m;++j)
c[i+j]=(c[i+j]+1ll*a[i]*b[j])%Mod;
return c;
}
init_r(t);
a.rez(len);NTT(a,1);
b.rez(len);NTT(b,1);
for(int i=0;i<len;++i)a[i]=1ll*a[i]*b[i]%Mod;
return NTT(a,-1),a.rez(t),a;
}
poly poly_mul(poly a,poly b){
int n=a.size(),m=b.size(),t=n+m-1;
if(n<=30||m<=30){
poly c(t);
for(int i=0;i<n;++i)
if(a[i])
for(int j=0;j<m;++j)
c[i+j]=(c[i+j]+1ll*a[i]*b[j])%Mod;
return c;
}
init_r(t);
a.rez(len);NTT(a,1);
b.rez(len);NTT(b,1);
for(int i=0;i<len;++i)a[i]=1ll*a[i]*b[i]%Mod;
return NTT(a,-1),a.rez(t),a;
}
poly poly_inv(poly a,int K){
poly b(1,Fast_Pow(a[0],Mod-2)),c;
for(int i=1,l=2,n=a.size();i<K;i<<=1,l<<=1){
init_r(l<<1);c.rez(l);
for(int j=0;j<l;++j)c[j]=j<n?a[j]:0;
c.rez(len);NTT(c,1);
b.rez(len);NTT(b,1);
for(int j=0;j<len;++j)b[j]=1ll*b[j]*(2-1ll*b[j]*c[j]%Mod+Mod)%Mod;
NTT(b,-1);b.rez(l);
}
return b.rez(K),b;
}
poly poly_sqrt(poly a,int K){
poly b(1,QR::calc(a[0])),c,binv;
for(int i=1,l=2,n=a.size();i<K;i<<=1,l<<=1){
binv=poly_inv(b,l);
c.rez(l);
for(int j=0;j<l;++j)c[j]=j<n?a[j]:0;
c=c*binv;
c.rez(l);b.rez(l);
for(int j=0;j<l;++j)b[j]=1ll*inv[2]*(c[j]+b[j])%Mod;
}
return b.rez(K),b;
}
poly poly_deriv(poly a){
int n=a.size();
for(int i=1;i<n;++i)a[i-1]=1ll*a[i]*i%Mod;
a.pop_back();
return a;
}
poly poly_integ(poly a){
int n=a.size();
a.push_back(0);
for(int i=n-1;i>=0;--i)a[i+1]=1ll*a[i]*inv[i+1]%Mod;
a[0]=0;
return a;
}
poly poly_ln(poly a,int K){
a=poly_deriv(a)*poly_inv(a,K);
a.rez(K-1);
return poly_integ(a);
}
poly poly_exp(poly a,int K){
poly b(1,1),c;
for(int i=1,l=2,n=a.size();i<K;i<<=1,l<<=1){
c.rez(l);
for(int j=0;j<l;++j)c[j]=j<n?a[j]:0;
c[0]=add(c[0],1);
b=b*(c-poly_ln(b,l));b.rez(l);
}
return b.rez(K),b;
}
const int B=32;
const int Bbit=5;
int F[1<<20|5],A[1<<20|5],L,tim=0;
poly BitF[23][B],tmp;
vector<int> H[23][B];
void cdq(int l,int r){
if(r-l+1<=64){
for(int i=l;i<=r;++i){
A[i]=1ll*A[i]*inv[i]%Mod;
for(int j=1;j<=r-i;++j)
A[i+j]=(A[i+j]+1ll*A[i]*F[j])%Mod;
}
return;
}
int lenB=(r-l+1)/B;
int gg=0;while((1<<gg)<lenB)gg++;
for(int i=1;i<B;++i){
H[gg][i].rez(lenB<<1);
for(int j=0;j<lenB*2;++j)H[gg][i][j]=0;
}
for(int i=0;i<B;++i){
if(i){
init_r(lenB<<1);
NTT(H[gg][i],-1);
for(int j=0;j<lenB;++j)A[l+i*lenB+j]=add(A[l+i*lenB+j],H[gg][i][j+lenB]);
}
cdq(l+i*lenB,l+(i+1)*lenB-1);
tmp.rez(lenB<<1);
for(int j=0;j<lenB;++j)tmp[j]=A[l+i*lenB+j];
for(int j=lenB;j<lenB*2;++j)tmp[j]=0;
init_r(lenB<<1);
NTT(tmp,1);
for(int j=i+1;j<B;++j){
for(int k=0;k<lenB*2;++k)
H[gg][j][k]=(H[gg][j][k]+1ll*BitF[bit-1][j-i-1][k]*tmp[k])%Mod;
}
}
}
poly Poly_exp(poly a,int K){
if(a.size()==1){
poly c(K);
c[0]=1;
return c;
}
L=1;tim=0;
while(L<K)L<<=1,tim++;
if(a.size()<L)a.rez(L);
F[0]=0;
for(int i=1;i<=L-1;++i)F[i]=1ll*a[i]*i%Mod;
//0~L-1 1~L-1
int at=L,z=tim;
while(z>=Bbit){
at/=B;z-=Bbit;
for(int i=0;i<B-1;++i){
BitF[z][i].rez(at*2);
for(int j=0;j<at*2;++j)BitF[z][i][j]=F[i*at+j];
init_r(at*2);
NTT(BitF[z][i],1);
}
}
A[0]=1;
for(int i=1;i<=L-1;++i)A[i]=0;
cdq(0,L-1);
poly c(K);
for(int i=0;i<K;++i)c[i]=A[i];
return c;
}
poly Div(poly a,poly b){
int n=a.size()-1,m=b.size()-1;
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
b=poly_inv(b,n-m+1);
a=a*b;
a.rez(n-m+1);
reverse(a.begin(),a.end());
return a;
}
poly Left(poly a){
for(int i=0;i<a.size()-1;++i)a[i]=a[i+1];
a.pop_back();
return a;
}
poly Right(poly a){
int t=a.size();a.rez(t+1);
for(int i=a.size()-2;i>=0;--i)a[i+1]=a[i];
a[0]=0;
return a;
}
poly poly_pow(poly a,int K,int m){//末项非0
int t=a[0],invt=Fast_Pow(t,Mod-2),ft=Fast_Pow(t,m);
for(int i=0;i<a.size();++i)a[i]=1ll*a[i]*invt%Mod;
poly b=poly_ln(a,K);
for(int i=0;i<K;++i)b[i]=1ll*b[i]*m%Mod;
b=Poly_exp(b,K);
for(int i=0;i<K;++i)b[i]=1ll*b[i]*ft%Mod;
return b;
}
}