模板库&&一些小技巧?

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
#include
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  "<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"<1) {
        //if(!iscut[u])
        ++ans;//根节点不可能被统计多次
        iscut[u]=1;
        //	cout<<"fa "<>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<

求割边
来自这里

void Tarjan(int u,int fa)
{
    dfn[u] = low[u] = ++indx;
    stk.push(u);
    int flg = 0;
    for(int i=0; idfn[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
#include
#include
#include
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]]'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)!} (di1)!(n2)!

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β)

你可能感兴趣的:(模板库&&一些小技巧?)