【Code Library】不超过25个页面的材料

---------------

一、模板

---

1、NGUNSTTD-PO

Name: NeverGiveUpNeverSurrenderTerribleTerribleDamage-PowerOverwhelming
Usage: Put it before main function
Tags: 头文件 循环 常用语句

---

/** head-file **/

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <set>
#include <map>
#include <algorithm>

/** define-for **/

#define REP(i, n) for (int i=0;i<int(n);++i)
#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
#define REP_1(i, n) for (int i=1;i<=int(n);++i)
#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
#define REP_N(i, n) for (i=0;i<int(n);++i)
#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
#define REP_1_N(i, n) for (i=1;i<=int(n);++i)
#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)

/** define-useful **/

#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) int(x.size())
#define see(x) cerr<<#x<<" "<<x<<endl
#define se(x) cerr<<" "<<x
#define pb push_back
#define mp make_pair

/** test **/

#define Display(A, n, m) {                      \
    REP(i, n){                                  \
        REP(j, m) cout << A[i][j] << " ";       \
        cout << endl;                           \
    }                                           \
}

#define Display_1(A, n, m) {                    \
    REP_1(i, n){                                \
        REP_1(j, m) cout << A[i][j] << " ";     \
        cout << endl;                           \
    }                                           \
}

using namespace std;

/** typedef **/

typedef long long LL;

/** Add - On **/

const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };

const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const long long INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;
---

---------------

二、图论

---

1 建图

---

const int maxn=111111;
const int maxm=511111;
int n,m;

struct EDGENODE{
    int to;
    int w;
    int next;
};
struct SGRAPH{
    int head[maxn];
    EDGENODE edges[maxm];
    int edge;
    void init()
    {
        clr(head,-1);
        edge=0;
    }
    void addedge(int u,int v,int c=0)
    {
        edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
    }
}solver;
---

2 最短路

---

2.1 堆优化的dijkstra

---

const int maxn=11111;
const int maxm=1111111;

struct EdgeNode{
    int to;
    int w;
    int next;
};

struct HeapNode{
    int d,u;
    bool operator<(const HeapNode& rhs) const{
        return d>rhs.d;
    }
};

struct Dijkstra{
    EdgeNode edges[maxm];
    int head[maxn];
    int edge,n;
    void init(int n){
        this->n=n;
        memset(head,-1,sizeof(head));
        edge=0;
    }
    void addedges(int u,int v,int c){
        edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
    }
    bool done[maxn];
    int dis[maxn];
    int pre[maxn];
    void dijkstra(int s){
        priority_queue<HeapNode>que;
        for (int i=0;i<n;i++) dis[i]=INF;
        dis[s]=0;
        memset(done,0,sizeof(done));
        que.push((HeapNode){0,s});
        while (!que.empty()){
            HeapNode x=que.top();
            que.pop();
            int u=x.u;
            if (done[u]) continue;
            done[u]=true;
            for (int i=head[u];i!=-1;i=edges[i].next){
                int v=edges[i].to;
                int w=edges[i].w;
                if (dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    pre[v]=u;
                    que.push((HeapNode){dis[v],v});
                }
            }
        }
    }
}solver;

---

2.2 队列优化的Bellman-Ford

---

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxm=111111;
const int maxn=11111;
struct EdgeNode{
    int to;
    int w;
    int next;
};struct BellmanFord{
    EdgeNode edges[maxm];
    int head[maxn],edge,n;
    bool vis[maxn];
    int outque[maxn];
    queue<int>que;
    int dis[maxn];
    void addedge(int u,int v,int c){
        edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
    }
    void init(int n){
        memset(head,-1,sizeof(head));
        edge=0;
        this->n=n;
    }
    bool spfa(int s){
        int u;
        for (int i=0;i<=n;i++) dis[i]=INF;
        memset(vis,0,sizeof(vis));
        memset(outque,0,sizeof(outque));
        while (!que.empty()) que.pop();
        que.push(s);
        vis[s]=true;
        dis[s]=0;
        while (!que.empty()){
            u=que.front();
            que.pop();
            vis[u]=false;
            outque[u]++;
            if (outque[u]>n) return false;
            for (int i=head[u];i!=-1;i=edges[i].next){
                int v=edges[i].to;
                int w=edges[i].w;
                if (dis[v]==INF||dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    if (!vis[v]){
                        vis[v]=true;
                        que.push(v);
                    }
                }
            }
        }
        return true;
    }
};


---

3 连通性

---

3.1 强连通分量Tarjan模板

---

const int maxn=111111;
const int maxm=511111;
int n,m;

struct EDGENODE{
    int to;
    int w;
    int next;
};
struct SGRAPH{
    int head[maxn];
    EDGENODE edges[maxm];
    int edge;
    void init(int n)
    {
        clr(head,-1);
        edge=0;
    }
    void addedge(int u,int v,int c=0)
    {
        edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
    }
    int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;
    stack<int>stk;
    void dfs(int u)
    {
        pre[u]=lowlink[u]=++dfs_clock;
        stk.push(u);
        for (int i=head[u];i!=-1;i=edges[i].next){
            int v=edges[i].to;
            if (!pre[v]){
                dfs(v);
                lowlink[u]=min(lowlink[u],lowlink[v]);
            } else if (!sccno[v]){
                lowlink[u]=min(lowlink[u],pre[v]);
            }
        }
        if (lowlink[u]==pre[u]){
            scc_cnt++;
            int x;
            do{
                x=stk.top();
                stk.pop();
                sccno[x]=scc_cnt;
            }while (x!=u);
        }
    }
    void find_scc(int n)
    {
        dfs_clock=scc_cnt=0;
        clr(sccno,0);
        clr(pre,0);
        while (!stk.empty()) stk.pop();
        REP(i,n) if (!pre[i]) dfs(i);
    }
}solver;
---

3.2 双连通模板

---

const int maxn=1111;
const int maxm=5111;
int n,m;

struct EDGENODE{
    int to;
    int w;
    bool cut;
    int next;
};
struct SEDGE{
    int u;
    int v;
    SEDGE(int uu=0,int vv=0){u=uu;v=vv;}
};
struct BCC_GRAPH{
    int head[maxn];
    EDGENODE edges[maxm];
    int edge;
    void init()
    {
        clr(head,-1);
        edge=0;
    }
    void addedge(int u,int v,int c=0)
    {
        edges[edge].cut=0,edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
    }
    //BCC_Tarjan
    int dfn[maxn],low[maxn],bccno[maxn],dfs_clock,bcc_cnt;
    bool iscut[maxn];
    vector<int>bcc[maxn];
    stack<SEDGE>stk;
    int dfs(int u,int fa)
    {
        int lowu=dfn[u]=++dfs_clock;
        int child=0;
        for (int i=head[u];i!=-1;i=edges[i].next)
        {
            int v=edges[i].to;
            if (v==fa) continue;
            SEDGE e=SEDGE(u,v);
            if (!dfn[v])
            {
                stk.push(e);
                child++;
                int lowv=dfs(v,u);
                lowu=min(lowu,lowv);
                if (dfn[u]<=lowv) //cut 割点
                {
                    iscut[u]=true;
                    //done 点双连通
                    bcc_cnt++;
                    bcc[bcc_cnt].clear();
                    SEDGE x;
                    do{
                        x=stk.top();
                        stk.pop();
                        if (bccno[x.u]!=bcc_cnt)
                        {
                            bcc[bcc_cnt].push_back(x.u);
                            bccno[x.u]=bcc_cnt;
                        }
                        if (bccno[x.v]!=bcc_cnt)
                        {
                            bcc[bcc_cnt].push_back(x.v);
                            bccno[x.v]=bcc_cnt;
                        }
                    }while (x.u!=u||x.v!=v);
                    //over
                }
                if (dfn[u]<lowv)  //cut 桥
                {
                    edges[i].cut=true;
                    edges[i^1].cut=true;
                }
            }
            else if (dfn[v]<dfn[u])
            {
                stk.push(e);//done
                lowu=min(lowu,dfn[v]);
            }
        }
        if (fa<0&&child==1) iscut[u]=0;
        low[u]=lowu;
        return lowu;
    }
    void find_bcc(int n)
    {
        while (!stk.empty()) stk.pop();
        clr(dfn,0);
        clr(iscut,0);
        clr(bccno,0);
        dfs_clock=bcc_cnt=0;
        REP_1(i,n)
        {
            if (!dfn[i]) dfs(i,-1);
        }
    }
    //another
    int block[maxn];
    int vis[maxn];
    int b_num;
    void b_dfs(int u)
    {
        vis[u]=true;
        block[u]=b_num;
        for (int i=head[u];i!=-1;i=edges[i].next)
        {
            if (edges[i].cut) continue;
            int v=edges[i].to;
            if (!vis[v]) b_dfs(v);
        }
    }
    void find_block(int n)
    {
        //find_block 边双连通
        clr(block,0);
        clr(vis,0);
        b_num=0;
        REP_1(i,n)
        {
            if (!vis[i])
            {
                b_num++;
                b_dfs(i);
            }
        }
    }
}solver;
---

4 2-SAT

---

4.1 TwoSAT模板

---

const int maxn=2111;
const int maxm=2111111;
int n,m;
struct EDGENODE{
    int to;
    int next;
};
struct TWO_SAT{
    int head[maxn*2];
    EDGENODE edges[maxm*2];
    int edge;
    int n;
    bool mark[maxn*2];
    int S[maxn*2],c;
    void init(int n){
        this->n=n;
        clr(mark,0);
        clr(head,-1);
        edge=0;
    }
    void addedge(int u,int v){
        edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
    }
    // x = xval or y = yval
    void add_clause(int x,int xval,int y,int yval){
        x=x*2+xval;
        y=y*2+yval;
        addedge(x^1,y);
        addedge(y^1,x);
    }
    void add_con(int x,int xval){
        x=x*2+xval;
        addedge(x^1,x);
    }
    bool dfs(int x){
        if (mark[x^1]) return false;
        if (mark[x]) return true;
        mark[x]=true;
        S[c++]=x;
        for (int i=head[x];i!=-1;i=edges[i].next)
            if (!dfs(edges[i].to)) return false;
        return true;
    }
    bool solve(){
        for (int i=0;i<n*2;i+=2)
            if (!mark[i]&&!mark[i+1]){
                c=0;
                if (!dfs(i)){
                    while (c>0) mark[S[--c]]=false;
                    if (!dfs(i+1)) return false;
                }
            }
        return true;
    }
}TwoSAT;
---

4.2 强连通Tarjan高效2-SAT

---

const int maxn=11111;
const int maxm=2111111;
int n,m;
struct EDGENODE{
    int to;
    int next;
};
struct TWO_SAT{
    int head[maxn*2];
    EDGENODE edges[maxm*2];
    int edge;
    int n;
    void init(int n){
        this->n=2*n;
        clr(head,-1);
        edge=0;
    }
    void addedge(int u,int v){
        edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
    }
    // x = xval or y = yval
    void add_clause(int x,int xval,int y,int yval){
        x=x*2+xval;
        y=y*2+yval;
        addedge(x^1,y);
        addedge(y^1,x);
    }
    //x=xval
    void add_con(int x,int xval){
        x=x*2+xval;
        addedge(x^1,x);
    }
    //
    void add_self(int x,int xval,int y,int yval){
        x=x*2+xval;
        y=y*2+yval;
        addedge(x,y);
    }
    int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;
    stack<int>stk;
    void dfs(int u)
    {
        pre[u]=lowlink[u]=++dfs_clock;
        stk.push(u);
        for (int i=head[u];i!=-1;i=edges[i].next){
            int v=edges[i].to;
            if (!pre[v]){
                dfs(v);
                lowlink[u]=min(lowlink[u],lowlink[v]);
            } else if (!sccno[v]){
                lowlink[u]=min(lowlink[u],pre[v]);
            }
        }
        if (lowlink[u]==pre[u]){
            scc_cnt++;
            int x;
            do{
                x=stk.top();
                stk.pop();
                sccno[x]=scc_cnt;
            }while (x!=u);
        }
    }
    void find_scc(int n)
    {
        dfs_clock=scc_cnt=0;
        clr(sccno,0);
        clr(pre,0);
        while (!stk.empty()) stk.pop();
        REP(i,n) if (!pre[i]) dfs(i);
    }
    bool solve(){
        find_scc(n);
        for (int i=0;i<n;i+=2){
            if (sccno[i]==sccno[i^1]) return false;
        }
        return true;
    }
}TwoSAT;
---

5 网络流

---

5.1 最大流模板Dinic

---

const int INF = 0x3f3f3f3f;
const int maxm=11111;
const int maxn=2222;
struct edgenode{
    int to,flow,next;
};
struct Dinic  {
    int node,src,dest,edge;
    int head[maxn],work[maxn],dis[maxn],q[maxn];
    edgenode edges[maxm];
    void prepare(int _node,int _src,int _dest){
        node=_node,src=_src,dest=_dest;
        memset(head,-1,sizeof(head));
        edge=0;
    }
    void addedge(int u,int v,int c){
        edges[edge].flow=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
        edges[edge].flow=0,edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++;
    }
    bool Dinic_bfs()  {
        int i,u,v,l,r=0;
        for (i=0; i<node; i++) dis[i]=-1;
        dis[q[r++]=src]=0;
        for (l=0; l<r; l++){
            for (i=head[u=q[l]]; i!=-1; i=edges[i].next){
                if (edges[i].flow&&dis[v=edges[i].to]<0){
                    dis[q[r++]=v]=dis[u]+1;
                    if (v==dest) return true;
                }
            }
        }
        return false;
    }
    int Dinic_dfs(int u,int exp){
        if (u==dest) return exp;
        for (int &i=work[u],v,tmp; i!=-1; i=edges[i].next){
            if (edges[i].flow&&dis[v=edges[i].to]==dis[u]+1&&
                (tmp=Dinic_dfs(v,min(exp,edges[i].flow)))>0){
                edges[i].flow-=tmp;
                edges[i^1].flow+=tmp;
                return tmp;
            }
        }
        return 0;
    }
    int Dinic_flow(){
        int i,ret=0,delta;
        while (Dinic_bfs()){
            for (i=0; i<node; i++) work[i]=head[i];
            while ( delta=Dinic_dfs(src,INF) ) ret+=delta;
        }
        return ret;
    }
}solver;


---

5.2 最小费用最大流

---

const int INF=0x3f3f3f3f;//无穷大
const int maxm=1111111;//边的最大数量,为原图的两倍
const int maxn=2222;//点的最大数量
struct edgenode{
    int to;//边的指向
    int flow;//边的容量
    int cost;//边的费用
    int next;//链表的下一条边
};
struct MinCost{
    edgenode edges[maxm];
    int node,src,dest,edge;//node节点数,src源点,dest汇点,edge边数
    int head[maxn],p[maxn],dis[maxn],q[maxn],vis[maxn];//head链表头,p记录可行流上节点对应的反向边,dis计算距离
    void prepare(int _node=0,int _src=0,int _dest=0){
        node=_node,src=_src,dest=_dest;
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        edge=0;
    }
    void addedge(int u,int v,int f,int c){
        printf("u=%d v=%d f=%d c=%d\n",u,v,f,c);
        edges[edge].flow=f;edges[edge].cost=c;edges[edge].to=v;
        edges[edge].next=head[u];head[u]=edge++;
        edges[edge].flow=0;edges[edge].cost=-c;edges[edge].to=u;
        edges[edge].next=head[v];head[v]=edge++;
    }
    bool spfa(){
        int i,u,v,l,r=0,tmp;
        for (i=0;i<node;i++) dis[i]=INF;
        dis[q[r++]=src]=0;
        p[src]=p[dest]=-1;
        for (l=0;l!=r;((++l>=maxn)?l=0:l)){
            for (i=head[u=q[l]],vis[u]=false;i!=-1;i=edges[i].next){
                if (edges[i].flow&&dis[v=edges[i].to]>(tmp=dis[u]+edges[i].cost)){
                    dis[v]=tmp;
                    p[v]=i^1;
                    if (vis[v]) continue;
                    vis[q[r++]=v]=true;
                    if (r>=maxn) r=0;
                }
            }
        }
        return p[dest]>=0;
    }
    int spfaflow(){
        int i,ret=0,delta;
        while (spfa()){//按记录原路返回求流量
            for (i=p[dest],delta=INF;i>=0;i=p[edges[i].to]){
                delta=min(delta,edges[i^1].flow);
            }
            for (int i=p[dest];i>=0;i=p[edges[i].to]){
                edges[i].flow+=delta;
                edges[i^1].flow-=delta;
            }
            ret+=delta*dis[dest];
        }
        return ret;
    }
    void output(int u){
        cout<<u<<endl;
        for (int i=head[u];i!=-1;i=edges[i].next){
            int v=edges[i].to;
            if (edges[i].flow==0&&((i&1)==0)) output(v);
        }
    }
}solver;

---

-------------

6 无向图最小割 (New)

-----

struct StoerWagner{
    int mat[maxn][maxn];
    int dis[maxn];
    int S,T;
    int n;
    bool vis[maxn],del[maxn];
    void init(int n){
        memset(mat,0,sizeof(mat));
        this->n=n;
    }
    void addedge(int u,int v,int c){
        mat[u][v]+=c;
        mat[v][u]+=c;
    }
    int search(int ct){
        int tmp,mx,cut;
        memset(vis,0,sizeof(vis));
        memset(dis,0,sizeof(dis));
        T=S=-1;
        for (int i=0;i<n-ct;i++){
            mx=-1;
            for (int j=0;j<n;j++){
                if (!vis[j]&&!del[j]&&dis[j]>mx){
                    mx=dis[j];
                    tmp=j;
                }
            }
            S=T;
            T=tmp;
            cut=mx;
            vis[T]=true;
            for (int j=0;j<n;j++){
                if (!vis[j]&&!del[j]){
                    dis[j]+=mat[T][j];
                }
            }
        }
        return cut;
    }
    int minimumCut(){
        int ans=INF;
        memset(del,0,sizeof(del));
        for (int i=0;i<n-1;i++){
            int cut=search(i);
            if (cut<ans) ans=cut;
            if (ans==0) return 0;
            del[T]=true;
            for (int j=0;j<n;j++){
                if (!del[j]){
                    mat[S][j]+=mat[T][j];
                    mat[j][S]+=mat[T][j];
                }
            }
        }
        return ans;
    }
};

----------------------

7 倍增LCA

------------------------

void preprocess(){  
    for (int i=1;i<=n;i++){  
        anc[i][0]=fa[i];  
        maxCost[i][0]=cost[i];  
        for (int j=1;(1<<j)<n;j++) anc[i][j]=-1;  
    }  
    for (int j=1;(1<<j)<n;j++){  
        for (int i=1;i<=n;i++){  
            if (anc[i][j-1]!=-1){  
                int a=anc[i][j-1];  
                anc[i][j]=anc[a][j-1];  
                maxCost[i][j]=max(maxCost[i][j-1],maxCost[a][j-1]);  
            }  
        }  
    }  
}  
int query(int p,int q){  
    int log;  
    if (L[p]<L[q]) swap(p,q);  
    for (log=1;(1<<log)<=L[p];log++);log--;  
    int ans=-INF;  
    for (int i=log;i>=0;i--){  
        if (L[p]-(1<<i)>=L[q]){  
            ans=max(ans,maxCost[p][i]);  
            p=anc[p][i];  
        }  
    }  
    if (p==q) return ans;  
    for (int i=log;i>=0;i--){  
        if (anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){  
            ans=max(ans,maxCost[p][i]);  
            p=anc[p][i];  
            ans=max(ans,maxCost[q][i]);  
            q=anc[q][i];  
        }  
    }  
    ans=max(ans,cost[p]);  
    ans=max(ans,cost[q]);  
    return ans;  
}  

8 树

8.1 树的重心

class CenterTree{
private:
    int sz[maxn];
    void dfs(int u,int pa){
        sz[u]=1;
        for (int i=head[u];i!=-1;i=edges[i].next){
            int v=edges[i].to;
            if (v==pa) continue;
            //if (tree[v].visit) continue;
            dfs(v,u);
            sz[u]+=sz[v];
        }
    }
public:
    int getCenter(int x){
        int p=0;
        dfs(x,p);
        int cap=sz[x]/2;
        bool found=true;
        while (found){
            found=false;
            for (int i=head[x];i!=-1;i=edges[i].next){
                int y=edges[i].to;
                //if (tree[y].visit) continue;
                if (y!=p&&sz[y]>cap){
                    found=true;
                    p=x;
                    x=y;
                    break;
                }
            }
        }
        return x;
    }
}coder;

8.2 树的中心

class TreeCenter{
private:
    int f[maxn];
    int dp[maxn];
    int M,MM;
    int dfs(int u,int pa){
        int m1=0,m2=0;
        for (int i=head[u];i!=-1;i=edges[i].next){
            int v=edges[i].to;
            if (v==pa) continue;
            int t=dfs(v,u);
            if (t>m1){
                m2=m1;
                m1=t;
                f[u]=i;
            }
            else if (t>m2){
                m2=t;
            }
        }
        if (M<m1+m2) MM=u,M=m1+m2;
        dp[u]=m1;
        return dp[u]+1;
    }
public:
    int getCenter(int n){
        M=-1;
        dfs(1,-1);
        if (M&1){
            while (dp[MM]*2>M+1) MM=edges[f[MM]].to;
            //int E=f[MM];
            addedge(MM,n+1);
            addedge(n+1,MM);
            addedge(edges[f[MM]].to,n+1);
            addedge(n+1,edges[f[MM]].to);
            MM=n+1;
        }
        else{
            //int E=0;
            while (dp[MM]*2>M) MM=edges[f[MM]].to;
        }
        return MM;
    }
}solver;




---------------

三、数据结构

---

1 树堆Treap

---

名次树 启发式合并

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

struct Node{
    Node* ch[2];//左右子树
    int fix;//优先级。数值越大,优先级越高
    int key;
    int size;//以它为根的子树的总结点数
    bool operator<(const Node& rhs) const {
        return fix<rhs.fix;
    }
    int cmp(int x) const{
        if (x==key) return -1;
        return x<key?0:1;
    }
    //名次树
    void maintain(){
        size=1;
        if (ch[0]!=NULL) size+=ch[0]->size;
        if (ch[1]!=NULL) size+=ch[1]->size;
    }
};

struct Treap{
    Node* root;
    Treap(){
        srand(time(0));
        root=NULL;
    }
    void removetree(Node* &t){
        if (t->ch[0]!=NULL) removetree(t->ch[0]);
        if (t->ch[1]!=NULL) removetree(t->ch[1]);
        delete t;
        t=NULL;
    }
    void clear(){
        srand(time(0));
        removetree(root);
    }
    Node* newNode(int v){
        Node* t=new Node;
        t->key=v;
        t->ch[0]=t->ch[1]=NULL;
        t->fix=rand();
        t->size=1;
        return t;
    }
    //d=0代表左旋,d=1代表右旋
    void rotate(Node* &o,int d){
        Node* k=o->ch[d^1];
        o->ch[d^1]=k->ch[d];
        k->ch[d]=o;
        o->maintain();
        k->maintain();
        o=k;
    }
    //在以o为根的子树中插入键值x,修改o
    void insert(Node* &o,int x){
        if (o==NULL) o=newNode(x);
        else{
            int d=o->cmp(x);
            if (d==-1) d=1;
            insert(o->ch[d],x);
            if (o->ch[d]>o) rotate(o,d^1);
        }
        o->maintain();
    }
    void remove(Node* &o,int x){
        int d=o->cmp(x);
        if (d==-1){
            Node* u=o;
            if (o->ch[0]!=NULL&&o->ch[1]!=NULL){
                int d2=(o->ch[0]>o->ch[1]?1:0);
                rotate(o,d2);
                remove(o->ch[d2],x);
            }else{
                if (o->ch[0]==NULL) o=o->ch[1];
                else if (o->ch[1]==NULL) o=o->ch[0];
                delete u;
            }
        }
        else remove(o->ch[d],x);
        if (o!=NULL) o->maintain();
    }
    bool find(Node* o,int x){
        while (o!=NULL){
            int d=o->cmp(x);
            if (d==-1) return 1;
            else o=o->ch[d];
        }
        return 0;
    }
    //第k大的值
    int kth(Node* o,int k){
        if (o==NULL||k<=0||k>o->size) return 0;
        int s=(o->ch[1]==NULL?0:o->ch[1]->size);
        if (k==s+1) return o->key;
        else if (k<=s) return kth(o->ch[1],k);
        else return kth(o->ch[0],k-s-1);
    }
    void merge(Node* &src){
        if (src->ch[0]!=NULL) merge(src->ch[0]);
        if (src->ch[1]!=NULL) merge(src->ch[1]);
        insert(root,src->key);
        delete src;
        src=NULL;
    }
};


---

2 伸展树Splay

---

2.1 My Splay v1.0

---

/**********************************************************************************
    Splay Tree v1.0 索引
    Node:
        void addIt(int ad) 区间添加ad
        void revIt() 区间翻转
        void upd() 更新结点,子树改变后使用
        void pushdown() 向下传递懒惰标记
    Splay:
        Node* newNode(int v,Node* f) 构造一个val值为v的节点,父节点为f,
        Node* build(int l,int r,Node* f) 构造区间[l,r],父节点为f;
        void rotate(Node* t,int d) 左旋右旋
        void splay(Node* t,Node* f) 将结点t伸展到f
        void select(int k) 返回第k个节点并伸展到f,不计虚拟结点
        Node*&get(int l, int r) 返回区间[l,r],即l-1旋转到根,r+1旋转到根的右儿子
        void reverse(int l,int r) 翻转区间[l,r]
        void split(int l,int r,Node*&s1) 将区间[l,r]剪切到s1
        void cut(int l,int r) 将区间[l,r]剪切到序列尾部
        void init(int n) 构造区间[1,n]并初始化
        void show(Node* rt) 输出树rt的中序遍历,debug用
        void output(int l,int r) 输出并伸展区间[l,r],复杂度较高待优化
    注意:
        每种修改操作(插入、删除、修改和翻转)过后,
        要将修改的结点(即根结点右子结点的左子结点)Splay到根的位置。
        删除操作要回收空间,可以人工压栈回收结点指针
**********************************************************************************/
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAX_N = 150000 + 10;
const int INF = ~0U >> 1;
struct Node{
    Node *ch[2],*pre;//左右子树,父节点
    int val;//关键字
    int size;//以它为根的子树的总结点数
    int mx;//最大值
    int add;//添加标记
    bool rev;//翻转标记
    Node(){
        size=0;
        val=mx=-INF;
        add=0;
    }
    void addIt(int ad){
        add+=ad;
        mx+=ad;
        val+=ad;
    }
    void revIt(){
        rev^=1;
    }
    void upd(){
        size=ch[0]->size+ch[1]->size+1;
        mx=max(val,max(ch[0]->mx,ch[1]->mx));
    }
    void pushdown();
}Tnull,*null=&Tnull;
void Node::pushdown(){
    if (add!=0){
        for (int i=0;i<2;++i)
            if (ch[i]!=null) ch[i]->addIt(add);
        add = 0;
    }
    if (rev){
        swap(ch[0],ch[1]);
        for (int i=0;i<2;i++)
            if (ch[i]!=null) ch[i]->revIt();
        rev = 0;
    }
}
struct Splay{
    Node nodePool[MAX_N],*cur;//内存分配
    Node* root;//根
    Splay(){
        cur=nodePool;
        root=null;
    }
    //清空内存,init()调用
    void clear(){
        cur=nodePool;
        root=null;
    }
    //新建节点,build()用
    Node* newNode(int v,Node* f){
        cur->ch[0]=cur->ch[1]=null;
        cur->size=1;
        cur->val=v;
        cur->mx=v;
        cur->add=0;
        cur->rev=0;
        cur->pre=f;
        return cur++;
    }
    //构造区间[l,r]中点m,init()使用
    Node* build(int l,int r,Node* f){
        if(l>r) return null;
        int m=(l+r)>>1;
        Node* t=newNode(m,f);
        t->ch[0]=build(l,m-1,t);
        t->ch[1]=build(m+1,r,t);
        t->upd();
        return t;
    }
    //旋转操作,c=0表示左旋,c=1表示右旋
    void rotate(Node* x,int c){
        Node* y=x->pre;
        y->pushdown();
        x->pushdown();
        //先将y结点的标记向下传递(因为y在上面)
        y->ch[!c]=x->ch[c];
        if (x->ch[c]!=null) x->ch[c]->pre=y;
        x->pre=y->pre;
        if (y->pre!=null)
        {
            if (y->pre->ch[0]==y) y->pre->ch[0]=x;
            else y->pre->ch[1]=x;
        }
        x->ch[c]=y;
        y->pre=x;
        y->upd();//维护y结点
        if (y==root) root=x;
    }
    //Splay操作,表示把结点x转到结点f的下面
    void splay(Node* x,Node* f){
        x->pushdown();//下传x的标记
        while (x->pre!=f){
            if (x->pre->pre==f){//父节点的父亲为f,执行单旋
                if (x->pre->ch[0]==x) rotate(x,1);
                else rotate(x,0);
            }else{
                Node *y=x->pre,*z=y->pre;
                if (z->ch[0]==y){
                    if (y->ch[0]==x) rotate(y,1),rotate(x,1);//一字型旋转
                    else rotate(x,0),rotate(x,1);//之字形旋转
                }else{
                    if (y->ch[1]==x) rotate(y,0),rotate(x,0);//一字型旋转
                    else rotate(x,1),rotate(x,0);//之字形旋转
                }
            }
        }
        x->upd();//最后再维护X结点
    }
    //找到处在中序遍历第k个结点,并将其旋转到结点f的下面
    void select(int k,Node* f){
        int tmp;
        Node* x=root;
        x->pushdown();
        k++;//空出虚拟节点
        for(;;){
            x->pushdown();
            tmp=x->ch[0]->size;
            if (k==tmp+1) break;
            if (k<=tmp) x=x->ch[0];
            else{
                k-=tmp+1;
                x=x->ch[1];
            }
        }
        splay(x,f);
    }
    //选择[l,r]
    Node*&get(int l, int r){
        select(l-1,null);
        select(r+1,root);
        return root->ch[1]->ch[0];
    }
    //翻转[l,r]
    void reverse(int l,int r){
        Node* o=get(l,r);
        o->rev^=1;
        splay(o,null);
    }
    //剪切出[l,r]到s1
    void split(int l,int r,Node*&s1)
    {
        Node* tmp=get(l,r);
        s1=tmp;
        root->ch[1]->ch[0]=null;
        splay(root->ch[1],null);
    }
    void cut(int l,int r)
    {
        Node* tmp;
        split(l,r,tmp);
        select(root->size-1,null);
        select(root->size-2,root);
        root->ch[0]->ch[1]=tmp;
        tmp->pre=root->ch[0];
        splay(tmp,null);
    }
    //初始化
    void init(int n){
        clear();
        root=newNode(0,null);
        root->ch[1]=newNode(n+1,root);
        root->ch[1]->ch[0]=build(1,n,root->ch[1]);
        splay(root->ch[1]->ch[0],null);
    }
    //输出中序遍历,debug用
    void show(Node* rt){
        if (rt==null) return;
        if (rt->ch[0]!=null) show(rt->ch[0]);
        cerr<<"rt="<<rt->val;
        if (rt->ch[0]!=null) cerr<<" l="<<rt->ch[0]->val;
        if (rt->ch[1]!=null) cerr<<" r="<<rt->ch[1]->val;
        if (rt->pre  !=null) cerr<<" pre="<<rt->pre->val;
        cerr<<endl;
        if (rt->ch[1]!=null) show(rt->ch[1]);
    }
    //按序输出
    void output(int l,int r){
        for (int i=l;i<=r;i++){
            select(i,null);
            cout<<root->val<<endl;
        }
        //cout<<endl;
    }

}T;
int main()
{
    int n,m,a,b;
    while (~scanf("%d%d",&n,&m))
    {
        T.init(n);
        while (m--)
        {
            scanf("%d%d",&a,&b);
            if (b<a) swap(a,b);
            T.reverse(a,b);
            T.cut(a,b);
        }
        T.output(1,n);
    }
    return 0;
}
---

2.2 BYVoid's Splay

---

/*
 * Problem: NOI2005 sequence
 * Author: Guo Jiabao
 * Time: 2009.5.30 14:19
 * State: Solved
 * Memo: 伸展树
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
const int MAXN=2850003,MAXL=500001,INF=1001;
struct SplayTree
{
    struct SplayNode
    {
        SplayNode *c[2],*f;
        int value,size,sum,maxsum,mls,mrs;
        bool rev,same;
    }*root,*null,*lb,*rb,SS[MAXN];
    int SC;
    SplayNode * NewNode(int value,SplayNode *f)
    {
        SplayNode *e=SS+ ++SC;
        e->value=value;
        e->size=1;e->f=f;
        e->sum=e->maxsum=e->mls=e->mrs=value;
        e->same=e->rev=false;
        e->c[0]=e->c[1]=null;
        return e;
    }
    inline int max(int a,int b){return a>b?a:b;}
    void update(SplayNode *p)
    {
        if (p==null) return;
        p->size = p->c[0]->size + p->c[1]->size + 1;
        p->sum = p->c[0]->sum + p->c[1]->sum + p->value;
        p->mls = p->c[0]->mls;
        p->mls = max( p->mls , p->c[0]->sum + p->value);
        p->mls = max( p->mls , p->c[0]->sum + p->value + p->c[1]->mls );
        p->mrs = p->c[1]->mrs;
        p->mrs = max( p->mrs , p->c[1]->sum + p->value);
        p->mrs = max( p->mrs , p->c[1]->sum + p->value + p->c[0]->mrs );
        p->maxsum = p->value;
        p->maxsum = max( p->maxsum , p->c[0]->maxsum );
        p->maxsum = max( p->maxsum , p->c[1]->maxsum );
        p->maxsum = max( p->maxsum , p->c[0]->mrs + p->value );
        p->maxsum = max( p->maxsum , p->c[1]->mls + p->value );
        p->maxsum = max( p->maxsum , p->c[0]->mrs + p->c[1]->mls + p->value );
    }
    void pushdown(SplayNode *p)
    {
        if (p==null) return;
        if (p->rev)
        {
            p->rev=false;
            SplayNode *q=p->c[0]; p->c[0]=p->c[1]; p->c[1]=q;
            p->c[0]->rev = !p->c[0]->rev;
            p->c[1]->rev = !p->c[1]->rev;
            int t=p->mls;
            p->mls=p->mrs; p->mrs=t;
        }
        if (p->same)
        {
            p->same=false;
            p->c[0]->same=p->c[1]->same=true;
            p->c[0]->value=p->c[1]->value=p->value;
            p->sum = p->maxsum = p->mls = p->mrs = p->value * p->size;
            if (p->value < 0)
                p->maxsum = p->mls = p->mrs = p->value;
        }
    }
    void rotate(SplayNode *x,int o)//Zig o=0 Zag o=1
    {
        SplayNode *y=x->f;
        pushdown(x->c[0]);
        pushdown(x->c[1]);
        pushdown(y->c[!o]);
        y->c[o] = x->c[!o];
        y->c[o]->f=y;
        x->f = y->f;
        if (y->f->c[0]==y)
            y->f->c[0]=x;
        else
            y->f->c[1]=x;
        y->f=x;
        x->c[!o]=y;
        update(y);
        update(x);
        if (root==y) root=x;
    }
    void splay(SplayNode *x,SplayNode *y)
    {
        pushdown(x);
        while (x->f!=y)
        {
            if (x->f->f==y)
            {
                if (x->f->c[0]==x)
                    rotate(x,0);
                else
                    rotate(x,1);
            }
            else if (x->f->f->c[0] == x->f)
            {
                if (x->f->c[0]==x)
                    rotate(x->f,0),rotate(x,0);
                else
                    rotate(x,1),rotate(x,0);
            }
            else
            {
                if (x->f->c[1]==x)
                    rotate(x->f,1),rotate(x,1);
                else
                    rotate(x,0),rotate(x,1);
            }
        }
    }
    void select(int k,SplayNode *y)
    {
        SplayNode *x=root;
        pushdown(x);
        for (;k != x->c[0]->size + 1;)
        {
            if (k <= x->c[0]->size)
                x=x->c[0];
            else
            {
                k-=x->c[0]->size + 1;
                x=x->c[1];
            }
            pushdown(x);
        }
        splay(x,y);
    }
    void Insert(int pos,int tot,int *C)
    {
        SplayNode *z,*t;
        z=t=NewNode(C[1],null);
        for (int i=2;i<=tot;i++)
            z=z->c[1]=NewNode(C[i],z);
        select(pos+1,null);
        select(pos+2,root);
        root->c[1]->c[0] = t;
        t->f=root->c[1];
        splay(z,null);
    }
    void Delete(int pos,int tot)
    {
        select(pos,null);
        select(pos+tot+1,root);
        root->c[1]->c[0] = null;
        splay(root->c[1],null);
    }
    void MakeSame(int pos,int tot,int value)
    {
        select(pos,null);
        select(pos+tot+1,root);
        root->c[1]->c[0]->same=true;
        root->c[1]->c[0]->value=value;
        splay(root->c[1]->c[0],null);
    }
    void Reverse(int pos,int tot)
    {
        select(pos,null);
        select(pos+tot+1,root);
        root->c[1]->c[0]->rev=!root->c[1]->c[0]->rev;
        splay(root->c[1]->c[0],null);
    }
    int GetSum(int pos,int tot)
    {
        select(pos,null);
        select(pos+tot+1,root);
        pushdown(root->c[1]->c[0]);
        return root->c[1]->c[0]->sum;
    }
    int MaxSum()
    {
        pushdown(root);
        update(root);
        return root->maxsum;
    }
    void init()
    {
        SC=-1;
        null=0;
        null=NewNode(-INF,0);
        null->size=0;
        lb=root=NewNode(-INF,null);
        rb=root->c[1]=NewNode(-INF,root);
        null->sum = lb->sum = rb->sum=0;
        update(root);
    }
}Splay;
int N,M,C[MAXL],pos,i,j,A;
char Ctrl[20];
int main()
{
    freopen("seq2005.in","r",stdin);
    freopen("seq2005.out","w",stdout);
    Splay.init();
    scanf("%d%d",&N,&M);
    for (i=1;i<=N;i++)
        scanf("%d",&C[i]);
    Splay.Insert(0,N,C);
    for (i=1;i<=M;i++)
    {
        scanf("%s",Ctrl);
        switch (Ctrl[0])
        {
            case 'I':
                scanf("%d%d",&pos,&N);
                for (j=1;j<=N;j++)
                    scanf("%d",&C[j]);
                Splay.Insert(pos,N,C);
                break;
            case 'D':
                scanf("%d%d",&pos,&N);
                Splay.Delete(pos,N);
                break;
            case 'R':
                scanf("%d%d",&pos,&N);
                Splay.Reverse(pos,N);
                break;
            case 'G':
                scanf("%d%d",&pos,&N);
                A=Splay.GetSum(pos,N);
                printf("%d\n",A);
                break;
            case 'M':
                if (Ctrl[2]=='K')
                {
                    scanf("%d%d%d",&pos,&N,&C[0]);
                    Splay.MakeSame(pos,N,C[0]);
                }
                else
                    printf("%d\n",Splay.MaxSum());
                break;
        }
    }
    return 0;
}


---

3 树状数组

---

struct BIT{
    int n;
    int tree[maxn];
    void init(int n){
        this->n=n;
        memset(tree,0,sizeof(tree));
    }
    int lowbit(int x){
        return x&(-x);
    }
    void add(int x,int val){
        for (int i=x;i<=n;i+=lowbit(i)) tree[i]+=val;
    }
    int query(int x){
        int ret=0;
        for (int i=x;i>0;i-=lowbit(i)) ret+=tree[i];
        return ret;
    }
    //离散 p=lower_bound(b+1,b+n+1,a[i])-b;
    //逆序数 x=(i-1)-query(p);add(p,1);
};

---

4 线段树

---

4.1 单点更新

---

const int MAXN=255111;
struct SegmentTree{
    int num[MAXN];
    struct Tree{
        int l;
        int r;
        int min;
    };
    Tree tree[MAXN*4];
    void push_up(int root){
        tree[root].min=min(tree[root<<1].min,tree[root<<1|1].min);
    }
    void build(int root,int l,int r){
        tree[root].l=l;
        tree[root].r=r;
        if(tree[root].l==tree[root].r){
            tree[root].min=num[l];
            return;
        }
        int mid=(l+r)/2;
        build(root<<1,l,mid);
        build(root<<1|1,mid+1,r);
        push_up(root);
    }
    void update(int root,int pos,int val){
        if(tree[root].l==tree[root].r){
            tree[root].min=val;
            return;
        }
        int mid=(tree[root].l+tree[root].r)/2;
        if(pos<=mid) update(root<<1,pos,val);
        else update(root<<1|1,pos,val);
        push_up(root);
    }
    int query(int root,int L,int R){
        if(L<=tree[root].l&&R>=tree[root].r) return tree[root].min;
        int mid=(tree[root].l+tree[root].r)/2,ret=INF;
        if(L<=mid) ret=min(ret,query(root<<1,L,R));
        if(R>mid) ret=min(ret,query(root<<1|1,L,R));
        return ret;
    }
    void init(int n,int d){
        for (int i=1;i<=n;i++) num[i]=d;
        build(1,1,n);
    }
};


---

4.2 区间维护

---

const int INF=0x3f3f3f;
const int MAXN=10000;
struct SegTree{
    int num[MAXN];
    int _min,_max,_sum;
    struct Tree{
        int l;
        int r;
        int max;
        int min;
        int sum;
        int add;
        int set;
    };
    Tree tree[MAXN*4];
    void push_up(int root){
        tree[root].max=max(tree[root<<1].max,tree[root<<1|1].max);
        tree[root].min=min(tree[root<<1].min,tree[root<<1|1].min);
        tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
    }
    void push_down(int root){
        if (tree[root].set!=-1){
            if (tree[root].l!=tree[root].r){
                //传递懒惰标记
                tree[root<<1].add=tree[root<<1|1].add=0;
                tree[root<<1].set=tree[root<<1|1].set=tree[root].set;
                //最更新大值
                tree[root<<1].max=tree[root<<1|1].max=tree[root].set;
                //更新最小值
                tree[root<<1].min=tree[root<<1|1].min=tree[root].set;
                //更新区间和
                tree[root<<1].sum=(tree[root<<1].r-tree[root<<1].l+1)*tree[root].set;
                tree[root<<1|1].sum=(tree[root<<1|1].r-tree[root<<1|1].l+1)*tree[root].set;
            }
            tree[root].set=-1;
        }
        if (tree[root].add>0){
            if (tree[root].l!=tree[root].r){
                //传递懒惰标记
                tree[root<<1].add+=tree[root].add;
                tree[root<<1|1].add+=tree[root].add;
                //更新最大值
                tree[root<<1].max+=tree[root].add;
                tree[root<<1|1].max+=tree[root].add;
                //更新最小值
                tree[root<<1].min+=tree[root].add;
                tree[root<<1|1].min+=tree[root].add;
                //更新区间和
                tree[root<<1].sum+=(tree[root<<1].r-tree[root<<1].l+1)*tree[root].add;
                tree[root<<1|1].sum+=(tree[root<<1|1].r-tree[root<<1|1].l+1)*tree[root].add;
            }
            tree[root].add=0;
        }
    }
    void build(int root,int l,int r){
        tree[root].l=l;
        tree[root].r=r;
        if(tree[root].l==tree[root].r){
            tree[root].max=num[l];
            tree[root].min=num[l];
            tree[root].sum=num[l];
            tree[root].add=0;
            tree[root].set=-1;
            return;
        }
        int mid=(l+r)/2;
        build(root<<1,l,mid);
        build(root<<1|1,mid+1,r);
        push_up(root);
    }
    void update_add(int root,int L,int R,int val){
        if(L<=tree[root].l&&R>=tree[root].r){
            tree[root].add+=val;
            tree[root].max+=val;
            tree[root].min+=val;
            tree[root].sum+=(tree[root].r-tree[root].l+1)*val;
            return;
        }
        push_down(root);
        int mid=(tree[root].l+tree[root].r)/2;
        if(L<=mid) update_add(root<<1,L,R,val);
        if(R>mid)  update_add(root<<1|1,L,R,val);
        push_up(root);
    }
    void update_set(int root,int L,int R,int val){
        if(L<=tree[root].l&&R>=tree[root].r){
            tree[root].set=val;
            tree[root].add=0;
            tree[root].max=val;
            tree[root].min=val;
            tree[root].sum=(tree[root].r-tree[root].l+1)*val;
            return;
        }
        push_down(root);
        int mid=(tree[root].l+tree[root].r)/2;
        if(L<=mid) update_set(root<<1,L,R,val);
        if (R>mid) update_set(root<<1|1,L,R,val);
        push_up(root);
    }
    void query(int root,int L,int R){
        if(L<=tree[root].l&&R>=tree[root].r){
            _min=min(_min,tree[root].min);
            _max=max(_max,tree[root].max);
            _sum+=tree[root].sum;
            return;
        }
        push_down(root);
        int mid=(tree[root].l+tree[root].r)/2;
        if(L<=mid) query(root<<1,L,R);
        if(R>mid) query(root<<1|1,L,R);
    }
};


---

---

5 并查集

---

int pa[maxn];
void makeset(int n){
    for (int i=0;i<=n;i++) pa[i]=i;
}
int findset(int x){
    if (x!=pa[x]) pa[x]=findset(pa[x]);
    return pa[x];
}
void unionset(int x,int y){
    x=findset(x);
    y=findset(y);
    if (x!=y) pa[x]=y;
}


---

6 RMQ

---

6.1 取最小值

---

    int d[maxn][20];
    //元素从1编号到n
    void RMQ_init(int A[],int n){
        for (int i=1;i<=n;i++) d[i][0]=A[i];
        for (int j=1;(1<<j)<=n;j++)
            for (int i=1;i+(1<<j)-1<=n;i++)
                d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
    }
    int RMQ(int L,int R){
        int k=0;
        while ((1<<(k+1))<=R-L+1) k++;
        return min(d[L][k],d[R-(1<<k)+1][k]);
    }

---

6.2 取最小值的下标

---

    int d[maxn][20];
    //元素从1编号到n
    void makeRmqIndex(int A[],int n){
        for(int i=1;i<=n;i++) d[i][0]=i;
        for(int j=1;(1<<j)<=n;j++)
            for(int i=1;i+(1<<j)-1<=n;i++)
                d[i][j] = A[d[i][j-1]] < A[d[i+(1<<(j-1))][j-1]]? d[i][j-1]:d[i+(1<<(j-1))][j-1];
    }
    int rmqIndex(int L,int R,int A[])
    {
        int k=0;
        while ((1<<(k+1))<=R-L+1) k++;
        return A[d[L][k]]<A[d[R-(1<<k)+1][k]]? d[L][k]:d[R-(1<<k)+1][k];
    }

---

7 LCA的RMQ解法

---

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int INF=0x3f3f3f;
const int maxn=111111;
const int maxm=111111;
int n,m;

struct EDGENODE{
    int to;
    int w;
    int next;
};
struct SGRAPH{
    int head[maxn];
    EDGENODE edges[maxm];
    int edge;
    void init(){
        memset(head,-1,sizeof(head));
        edge=0;
    }
    void addedge(int u,int v,int c){
        edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
    }
    //------------
    int d[maxn][20];
    //元素从1编号到n
    void makeRmqIndex(int A[],int n){
        for(int i=1;i<=n;i++) d[i][0]=i;
        for(int j=1;(1<<j)<=n;j++)
            for(int i=1;i+(1<<j)-1<=n;i++)
                d[i][j] = A[d[i][j-1]] < A[d[i+(1<<(j-1))][j-1]]? d[i][j-1]:d[i+(1<<(j-1))][j-1];
    }
    int rmqIndex(int L,int R,int A[])
    {
        int k=0;
        while ((1<<(k+1))<=R-L+1) k++;
        return A[d[L][k]]<A[d[R-(1<<k)+1][k]]? d[L][k]:d[R-(1<<k)+1][k];
    }
    //---------------------
    int E[maxn*2],R[maxn],D[maxn*2],mn;
    void dfs(int u,int p,int d){
        E[++mn]=u;
        D[mn]=d;
        R[u]=mn;
        for (int i=head[u];i!=-1;i=edges[i].next){
            int v=edges[i].to;
            if (v==p) continue;
            dfs(v,u,d+1);
            E[++mn]=u;
            D[mn]=d;
        }
    }
    void LCA_init(){
        mn=0;
        memset(R,0,sizeof(R));
        dfs(1,-1,1);
        makeRmqIndex(D,mn);
        getd(1,-1,0);
    }
    int LCA(int u,int v){
        if (R[u]>=R[v]) return E[rmqIndex(R[v],R[u],D)];
        else return E[rmqIndex(R[u],R[v],D)];

    }
    //--------------------
    int deep[maxn];
    void getd(int u,int p,int w){
        deep[u]=w;
        for (int i=head[u];i!=-1;i=edges[i].next){
            int v=edges[i].to;
            if (v==p) continue;
            getd(v,u,w+edges[i].w);
        }
    }
    int getDis(int u,int v){
        int lca=LCA(u,v);
        return deep[u]+deep[v]-deep[lca]*2;
    }
    int done(int x,int y,int z){
        int ans=INF,res=0;
        int lca1,lca2;

        lca1=LCA(x,y);
        res=deep[x]+deep[y]-deep[lca1]*2;
        lca2=LCA(lca1,z);
        res+=deep[lca1]+deep[z]-deep[lca2]*2;
        ans=min(ans,res);

        lca1=LCA(x,z);
        res=deep[x]+deep[z]-deep[lca1]*2;
        lca2=LCA(lca1,y);
        res+=deep[lca1]+deep[y]-deep[lca2]*2;
        ans=min(ans,res);

        lca1=LCA(y,z);
        res=deep[y]+deep[z]-deep[lca1]*2;
        lca2=LCA(lca1,x);
        res+=deep[lca1]+deep[x]-deep[lca2]*2;
        ans=min(ans,res);

        return ans;
    }
}solver;
---

---------------

四、字符串

---

1 字典树Trie

---

const int CHARSET = 26;
const int MAX_N_NODES = int(3e5) + 10;
struct TrieNode
{
    TrieNode* next[CHARSET];
    int num;//记录是不是一个单词
    int value;//记录单词出现的次数
    TrieNode(){
       memset(next,0,sizeof(next));
       value=0;
       num=0;
    }
    void clear(){
       memset(next,0,sizeof(next));
       value=0;
       num=0;
    }
}*root;
TrieNode nodePool[MAX_N_NODES],*cur;
TrieNode* newNode(){
	TrieNode* t = cur++;
	t->clear();
	return t;
}
void trieInit() {
	cur=nodePool;
	root=newNode();
}
//插入:
void insert(char* s){
    TrieNode* p=root;
    int k=0;
    while(s[k]!='\0'){
        if(!p->next[s[k]-'a']) p->next[s[k]-'a']=newNode();
        p=p->next[s[k]-'a'];
        p->num++;
        k++;
    }
    p->value=1;
}
//查找
int find(char* s){
    TrieNode* p=root;
    int k=0;
    while(s[k]!='\0'&&p->next[s[k]-'a']){
        p=p->next[s[k]-'a'];
        k++;
    }
    if(s[k]=='\0') return p->num;
    return 0;
}
//DP查找
void dpfind(char* s,int pos){
    TrieNode* p=root;
    int k=0;
    while(s[k]!='\0'&&p->next[s[k]-'a']){
        p=p->next[s[k]-'a'];
        if (p->value==1){
            //do something like dp...
            //f[pos+k+1]=(f[pos+k+1]+f[pos])%MOD;
        }
        k++;
    }
}

---

f[0]=1;
for (int i=1;i<=l;i++)
        if (f[i-1])  find(str+i,i-1);

---

2 扩展KMP

---

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MM=100005;
int next[MM],extand[MM];
char S[MM],T[MM];
void GetNext(const char *T){
     int len=strlen(T),a=0;
     next[0]=len;
     while(a<len-1 && T[a]==T[a+1]) a++;
     next[1]=a;
     a=1;
     for(int k=2;k<len;k++){
         int p=a+next[a]-1,L=next[k-a];
         if( (k-1)+L >= p){
             int j = (p-k+1)>0 ? (p-k+1) : 0;
             while(k+j<len && T[k+j]==T[j]) j++;
             next[k]=j;
             a=k;
         }
         else
             next[k]=L;
     }
}
void GetExtand(const char *S,const char *T){
     GetNext(T);
     int slen=strlen(S),tlen=strlen(T),a=0;
     int MinLen = slen < tlen ? slen : tlen;
     while(a<MinLen && S[a]==T[a]) a++;
     extand[0]=a;
     a=0;
     for(int k=1;k<slen;k++){
         int p=a+extand[a]-1, L=next[k-a];
         if( (k-1)+L >= p){
             int j= (p-k+1) > 0 ? (p-k+1) : 0;
             while(k+j<slen && j<tlen && S[k+j]==T[j]) j++;
             extand[k]=j;
             a=k;
         }
         else
             extand[k]=L;
     }
}
int main(){
    while(scanf("%s%s",S,T)==2){
         GetExtand(S,T);
         for(int i=0;i<strlen(T);i++)
             printf("%d ",next[i]);
         puts("");
         for(int i=0;i<strlen(S);i++)
             printf("%d ",extand[i]);
         puts("");
    }
    return 0;
}
---

3 Aho-Corasick自动机

---

const int CHARSET = 26;
const int MAX_N_NODES = int(3e5) + 10;

struct Aho_Corasick{
    struct Node{
        Node *next[CHARSET];
        Node *fail;
        int count;//记录当前前缀是完整单词出现的个数
        Node(){
            memset(next,0,sizeof(next));
            fail = NULL;
            count = 0;
        }
        void clear(){
            memset(next,0,sizeof(next));
            fail = NULL;
            count = 0;
        }
    };
    Node *root;
    Node nodePool[MAX_N_NODES], *cur;
    Node* newNode(){
        Node* t=cur++;
        t->clear();
        return t;
    }
    void init(){
        cur=nodePool;
        root=newNode();
    }
    void insert(char *str){
        Node* p=root;
        int i=0,index;
        while(str[i]){
            index=str[i]-'a';
            if(p->next[index]==NULL) p->next[index]=newNode();
            p=p->next[index];
            i++;
        }
        p->count++;
    }
    void build_ac_automation(){
        int i;
        queue<Node*>Q;
        root->fail=NULL;
        Q.push(root);
        while(!Q.empty()){
            Node* temp=Q.front();
            Q.pop();
            Node* p=NULL;
            for(i=0;i<CHARSET;i++){
                if(temp->next[i]!=NULL){//寻找当前子树的失败指针
                    p = temp->fail;
                    while(p!=NULL){
                        if(p->next[i]!=NULL){//找到失败指针
                            temp->next[i]->fail=p->next[i];
                            break;
                        }
                        p=p->fail;
                    }
                    if(p==NULL) temp->next[i]->fail=root;//无法获取,当前子树的失败指针为根
                    Q.push(temp->next[i]);
                }
            }
        }
    }
    int query(char *str){//询问str中包含n个关键字中多少种即匹配
        int i=0,cnt=0,index;
        Node* p = root;
        while(str[i]){
            index=str[i]-'a';
            while(p->next[index]==NULL&&p!=root) p=p->fail;//失配
            p=p->next[index];
            if(p==NULL) p = root;//失配指针为根
            Node* temp = p;
            while(temp!=root&&temp->count!=-1){//寻找到当前位置为止是否出现关键字
                cnt+=temp->count;
                temp->count=-1;
                temp=temp->fail;
            }
            i++;
        }
        return cnt;
    }
};


---

---

4 后缀数组

---

const int maxn=3e5*2+10;
/******************************************************************
**  后缀数组 Suffix Array
**  INIT:solver.call_fun(char* s);
**  CALL: solver.lcp(int i,int j); //后缀i与后缀j的最长公共前缀
**  SP_USE: solver.LCS(char *s1,char* s2); //最长公共字串
******************************************************************/
struct SuffixArray{
    int r[maxn];
    int sa[maxn],rank[maxn],height[maxn];
    int t[maxn],t2[maxn],c[maxn],n;
    int m;//模板长度
    void init(char* s){
        n=strlen(s);
        for (int i=0;i<n;i++) r[i]=int(s[i]);
        m=300;
    }
    int cmp(int *r,int a,int b,int l){
        return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    /**
    字符要先转化为正整数
    待排序的字符串放在r[]数组中,从r[0]到r[n-1],长度为n,且最大值小于m。
    所有的r[i]都大于0,r[n]无意义算法中置0
    函数结束后,结果放在sa[]数组中(名次从1..n),从sa[1]到sa[n]。s[0]无意义
    **/
    void build_sa(){
        int i,k,p,*x=t,*y=t2;
        r[n++]=0;
        for (i=0;i<m;i++) c[i]=0;
        for (i=0;i<n;i++) c[x[i]=r[i]]++;
        for (i=1;i<m;i++) c[i]+=c[i-1];
        for (i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
        for (k=1,p=1;k<n;k*=2,m=p){
            for (p=0,i=n-k;i<n;i++) y[p++]=i;
            for (i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;i++) c[i]=0;
            for (i=0;i<n;i++) c[x[y[i]]]++;
            for (i=1;i<m;i++) c[i]+=c[i-1];
            for (i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);
            p=1;
            x[sa[0]]=0;
            for (i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++;
        }
        n--;
    }
    /**
    height[2..n]:height[i]保存的是lcp(sa[i],sa[i-1])
    rank[0..n-1]:rank[i]保存的是原串中suffix[i]的名次
    **/
    void getHeight(){
        int i,j,k=0;
        for (i=1;i<=n;i++) rank[sa[i]]=i;
        for (i=0;i<n;i++){
            if (k) k--;
            j=sa[rank[i]-1];
            while (r[i+k]==r[j+k]) k++;
            height[rank[i]]=k;
        }
    }
    int d[maxn][20];
    //元素从1编号到n
    void RMQ_init(int A[],int n){
        for (int i=1;i<=n;i++) d[i][0]=A[i];
        for (int j=1;(1<<j)<=n;j++)
            for (int i=1;i+j-1<=n;i++)
                d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
    }
    int RMQ(int L,int R){
        int k=0;
        while ((1<<(k+1))<=R-L+1) k++;
        return min(d[L][k],d[R-(1<<k)+1][k]);
    }
    void LCP_init(){
        RMQ_init(height,n);
    }
    int lcp(int i,int j){
        if (rank[i]>rank[j]) swap(i,j);
        return RMQ(rank[i]+1,rank[j]);
    }
    void call_fun(char* s){
        init(s);//初始化后缀数组
        build_sa();//构造后缀数组sa
        getHeight();//计算height与rank
        LCP_init();//初始化RMQ
    }
    int LCS(char* s1,char* s2){
        int p,ans;
        int l=strlen(s1);
        p=l;
        s1[l]='$';
        s1[l+1]='\0';
        strcat(s1,s2);
        call_fun(s1);
        ans=0;
        for (int i=2;i<=n;i++)
            if ((sa[i-1]<p&&sa[i]>p)||(sa[i-1]>p&&sa[i]<p)) ans=max(ans,height[i]);
        return ans;
    }
}solver;

---

5 字符串hash

---

H(i)=s[i]+s[i+1]x+...s[n-2]x^(n-2-i)+s[n-1]x^(n-1-i)

Hash(i,L)=s[i]+s[i+1]x+...s[i+L-2]x^(L-2)+s[i+L-1]x^(L-1)

                 =H[i]-H[i+L]*x^L

对于LCP(i,j),二分答案L,判断Hash(i,L)与Hash(j,L)是否相等。

---

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;

typedef unsigned long long ULL;

const int SIZE = 100003;
const int SEED = 13331;
const int MAX_N = 50000 + 10;
char s[MAX_N];
struct HASH{
    ULL H[MAX_N];
    ULL XL[MAX_N];
    int len;
    HASH(){}
    void build(char *s){
        len=strlen(s);
        H[len]=0;
        XL[0]=1;
        for (int i=len-1;i>=0;i--){
            H[i]=H[i+1]*SEED+s[i];
            XL[len-i]=XL[len-i-1]*SEED;
        }
    }
    ULL hash(int i,int L){
        return H[i]-H[i+L]*XL[L];
    }
}hs;

LCP

int lcp(int i,int j){
    int l=0,r=min(len-i,len-j);
    int res=0;
    while (l<=r){
        int mid=(l+r)/2;
        if (hash(i,mid)==hash(j,mid)){
            res=mid;
            l=mid+1;
        }
        else{
            r=mid-1;
        }
    }
    return res;
}


---

6 后缀自动机

---

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define sz(x) int(x.size())
using namespace std;

typedef vector<int> VI;
const int maxn = 250000+10;

class SuffixAutomaton{
private:
    struct Node{
        Node *suf, *go[26];
        int val;
        Node(){
            suf=NULL;
            val=0;
            memset(go,0,sizeof(go));
        }
        void clear(){
            suf=NULL;
            val=0;
            memset(go,0,sizeof(go));
        }
        int calc(){
            if (suf==0) return 0;
            return val-suf->val;
        }
    };
    Node *root,*last;
    Node nodePool[maxn*2],*cur;
    Node* newNode(){
        Node* res=cur++;
        res->clear();
        return res;
    }
    int tot;
    void extend(int w){
        Node *p=last;
        Node *np=newNode();
        np->val=p->val+1;
        while (p&&!p->go[w]){
            p->go[w]=np;
            p=p->suf;
        }
        if (!p){
            np->suf=root;
            tot+=np->calc();
        }
        else{
            Node *q=p->go[w];
            if (p->val+1==q->val){
                np->suf=q;
                tot+=np->calc();
            }
            else{
                Node *nq=newNode();
                memcpy(nq->go,q->go,sizeof(q->go));
                tot-=p->calc()+q->calc();
                nq->val=p->val+1;
                nq->suf=q->suf;
                q->suf=nq;
                np->suf=nq;
                tot+=p->calc()+q->calc()+np->calc()+nq->calc();
                while (p&&p->go[w]==q){
                    p->go[w]=nq;
                    p=p->suf;
                }
            }
        }
        last = np;
    }
public:
    void init(){
        cur=nodePool;
        root=newNode();
        last=root;
    }
    VI getSubString(char s[]){
        VI v;
        tot=0;
        int len=strlen(s);
        for (int i=0;i<len;i++){
            extend(s[i]-'a');
            v.push_back(tot);
        }
        return v;
    }
    int getLCS(char A[],char B[]){
        int res=0,step=0;
        int lenA=strlen(A);
        int lenB=strlen(B);
        for (int i=0;i<lenA;i++) extend(A[i]-'a');
        Node *p=root;
        for (int i=0;i<lenB;i++){
            int x=B[i]-'a';
            if (p->go[x]){
                step++;
                p=p->go[x];
            }
            else{
                while (p&&!p->go[x]) p=p->suf;
                if (!p){
                    p=root;
                    step=0;
                }
                else{
                    step=p->val+1;
                    p=p->go[x];
                }
            }
            res=max(res,step);
        }
        return res;
    }
}atm;



---------------

五、几何

---

1 点·线

---

int dcmp(double x){
    if (fabs(x)<EPS) return 0;
    return x>0?1:-1;
}
struct point{
    double x,y;
    point(){}
    point(double _x,double _y):x(_x),y(_y){}
    /**运算操作**/
    bool operator==(point a)const{
        return dcmp(a.x-x)==0&&dcmp(a.y-y)==0;
    }
    bool operator<(point a)const{
        return dcmp(x-a.x)==0?dcmp(y-a.y)<0:dcmp(x-a.x)<0;
    }
    friend point operator+(point a,point b){
        return point(a.x+b.x,a.y+b.y);
    }//向量+向量=向量
    friend point operator-(point a,point b){
        return point(a.x-b.x,a.y-b.y);
    }//点-点=向量
    friend point operator*(point a,double p){
        return point(a.x*p,a.y*p);
    }//向量*数=向量
    friend point operator/(point a,double p){
        return point(a.x/p,a.y/p);
    }//向量/数=向量
    /**基本信息计算**/
    double len(){
        return hypot(x,y);
    }
    double len2(){
        return x*x+y*y;
    }
    double distance(point p){
        return hypot(x-p.x,y-p.y);
    }
    /**向量变换**/
    point rotate(double rad){
        return point(x*cos(rad)-y*sin(rad),x*sin(rad)+y*cos(rad));
    }//绕起点逆时针旋转rad
    point rotate(point p,double angle)//绕点p逆时针旋转angle角度
    {
        point v=(*this)-p;
        double c=cos(angle),s=sin(angle);
        return point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
    }
    point rotleft(){
        return point(-y,x);
    }//逆时针转90度
    point rotright(){
        return point(y,-x);
    }//顺时针转90度
    point normal(){
        double L=len();
        return point(-y/L,x/L);
    }//单位法线即左转90度长度归一
    point trunc(double r){
        double l=len();
        if (!dcmp(l)) return *this;
        r/=l;
        return point(x*r,y*r);
    }//长度变为r
    /**读入与输出**/
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    void output(){
        printf("%0.2f %0.2f\n",x,y);
    }
};
typedef point vect;
double dot(point a,point b){
    return a.x*b.x+a.y*b.y;
}
double cross(point a,point b){
    return a.x*b.y-a.y*b.x;
}
double area3p(point a,point b,point c){
    return cross(b-a,c-a)/2;
}//三角形abc的面积
double angle(vect a,vect b){
    return acos(dot(a,b)/a.len()/b.len());
}
point GetLineIntersection(point P,vect v,point Q,vect w){
    vect u=P-Q;
    double t=cross(w,u)/cross(v,w);
    return P+v*t;
}//直线交点
double ConvexPolygonArea(point *p,int n){
    double area=0;
    for (int i=1;i<n-1;i++) area+=cross(p[i]-p[0],p[i+1]-p[0]);
    return area/2;
}//多边形面积

struct line{
    point a,b;
    line(){}
    line(point _a,point _b){a=_a;b=_b;}
    line(point p,double angle){
        a=p;
        if (dcmp(angle-PI/2)==0) b=a+point(0,1);
        else b=a+point(1,tan(angle));
    }//倾斜角angle
    line (double _a,double _b,double _c){
        if (dcmp(_a)==0){
            a=point(0,-_c/_b);
            b=point(1,-_c/_b);
        }else if (dcmp(_b)==0){
            a=point(-_c/_a,0);
            b=point(-_c/_a,1);
        }else{
            a=point(0,-_c/_b);
            b=point(1,(-_c-_a)/_b);
        }
    }//ax+by+c=0
    void adjust(){
        if (b<a) swap(a,b);
    }//两点校准
    /**运算操作**/
    bool operator==(line v){
        return (a==v.a)&&(b==v.b);
    }
    /**基本信息计算**/
    double length(){
        return a.distance(b);
    }
    double angle(){
        double k=atan2(b.y-a.y,b.x-a.x);
        if (dcmp(k)<0) k+=PI;
        if (dcmp(k-PI)==0) k-=PI;
        return k;
    }
    /**线段相关**/
    int relation(point p){
        int c=dcmp(cross(p-a,b-a));
        if (c<0) return 1;//点在逆时针
        if (c>0) return 2;//点在顺时针
        return 3;//平行
    }
    bool pointonseg(point p){
        return dcmp(cross(p-a,b-a))==0&&dcmp(cross(p-a,p-b))<=0;
    }//点p在线段上?
    bool parallel(line v){
        return dcmp(cross(b-a,v.b-v.a))==0;
    }//与线段v平行?
    int segcrossseg(line v){
        int d1=dcmp(cross(b-a,v.a-a));
        int d2=dcmp(cross(b-a,v.b-a));
        int d3=dcmp(cross(v.b-v.a,a-v.a));
        int d4=dcmp(cross(v.b-v.a,b-v.a));
        if ((d1^d2)==-2&&(d3^d4)==-2)return 2;
        return ((d1==0&&dcmp(dot(v.a-a,v.a-b)<=0))||
                (d2==0&&dcmp(dot(v.b-a,v.b-b)<=0))||
                (d3==0&&dcmp(dot(a-v.a,a-v.b)<=0))||
                (d4==0&&dcmp(dot(b-v.a,b-v.b)<=0)));
    }//线段相交 0-不相交 1-非规范相交 2-规范相交
    /**直线相关**/
    int linecrosseg(line v){//直线v
        int d1=dcmp(cross(b-a,v.a-a));
        int d2=dcmp(cross(b-a,v.b-a));
        if ((d1^d2)==-2) return 2;
        return (d1==0||d2==0);
    }//0-平行 1-重合 2-相交
    int linecrossline(line v){
        if ((*this).parallel(v)) return v.relation(a)==3;
        return 2;
    }//0-平行 1-重合 2-相交
    point crosspoint(line v){
        double a1=cross(v.b-v.a,a-v.a);
        double a2=cross(v.b-v.a,b-v.a);
        return point((a.x*a2-b.x*a1)/(a2-a1),(a.y*a2-b.y*a1)/(a2-a1));
    }//交点
    double dispointtoline(point p){
        return fabs(cross(p-a,b-a))/length();
    }//点到线的距离
    double dispointtoseg(point p){
        if (dcmp(cross(p-b,a-b))<0||dcmp(cross(p-a,b-a))<0) return min(p.distance(a),p.distance(b));
        return dispointtoline(p);
    }
    /**输入输出**/
    void input(){
        a.input();
        b.input();
    }
    void output(){
        a.output();
        b.output();
    }
};
---

---------------

六、数学

---

2 数论基础

---

/*==============================================*\
 | 最大公约数-辗转相除
\*==============================================*/
int gcd(int a,int b){
    if (b==0) return a;
    return gcd(b,a%b);
}
/*==============================================*\
 | 扩展欧几里得
 | ax+by=gcd(a,b)
\*==============================================*/
int extgcd(int a,int b,int& x,int& y){
    int d=a;
    if (b!=0){
        d=extgcd(b,a%b,y,x);
        y-=(a/b)*x;
    }else{
        x=1;y=0;
    }
    return d;
}
/*==============================================*\
 | 素数-埃氏筛法
\*==============================================*/
int prime[maxn];
bool is_prime[maxn+1];
int sieve(int n){
    int p=0;
    for (int i=0;i<=n;i++) is_prime[i]=true;
    is_prime[0]=is_prime[1]=false;
    for (int i=2;i<=n;i++){
        if (is_prime[i]){
            prime[p++]=i;
            for (int j=2*i;j<=n;j+=i) is_prime[j]=false;
        }
    }
    return p;
}
/*==============================================*\
 | 快速幂
\*==============================================*/
LL modPow(LL x,LL n,LL mod){
    if (n==0) return 1;
    LL res=modPow(x*x%mod,n/2,mod);
    if (n&1) res=res*x%mod;
    return res;
}
/*==============================================*\
 | 高斯消元-列主元
 | 求解Ax=b,A为矩阵 无解/多解时返回空数组
\*==============================================*/
const double eps=1e-8;
typedef vector<double>vec;
typedef vector<vec>mat;
vec gaussJordan(const mat& A,const vec& b){
    int n=A.size();
    mat B(n,vec(n+1));
    for (int i=0;i<n;i++)
        for (int j=0;j<n;j++) B[i][j]=A[i][j];
    for (int i=0;i<n;i++) B[i][n]=b[i];
    for (int i=0;i<n;i++){
        int pivot=i;
        for (int j=i;j<n;j++){
            if (abs(B[j][i])>abs(B[pivot][i])) pivot=j;
        }
        swap(B[i],B[pivot]);
        if (abs(B[i][i]<eps)) return vec();//无解或多解
        for (int j=i+1;j<=n;j++) B[i][j]/=B[i][i];
        for (int j=0;j<n;j++){
            if (i!=j){
                for (int k=i+1;k<=n;k++) B[j][k]-=B[j][i]*B[i][k];
            }
        }
    }
    vec x(n);
    for (int i=0;i<n;i++) x[i]=B[i][n];
    return x;
}
/*==============================================*\
 | 逆元
 | ax≡b(mod m) x=a逆×b
 | gcd(a,m)!=1逆元不存在
\*==============================================*/
int modInverse(int a,int m){
    int x,y;
    extgcd(a,m,x,y);
    return (m+x%m)%m;
}
---

2 矩阵快速幂

---

/*==============================================*\
 | 矩阵快速幂
\*==============================================*/
const int M=10000;
typedef vector<int>vec;
typedef vector<vec>mat;
mat mul(mat &A,mat &B){
    mat C(A.size(),vec(B[0].size()));
    for (int i=0;i<(int)A.size();i++){
        for (int k=0;k<(int)B.size();k++){
            for (int j=0;j<(int)B[0].size();j++){
                C[i][j]=(C[i][j]+A[i][k]*B[k][j])%M;
            }
        }
    }
    return C;
}
mat pow(mat A,LL n){
    mat B(A.size(),vec(A.size()));
    for (int i=0;i<(int)A.size();i++){
        B[i][i]=1;
    }
    while (n>0){
        if (n&1) B=mul(B,A);
        A=mul(A,A);
        n>>=1;
    }
    return B;
}


---------------

七、其他

---

1 哈希Hash

---

1.1 普通hash

#include <iostream>
#include <cstring>
using namespace std;
const int maxn=11111;
const int maxh=10000019;
int head[maxh];
int next[maxh];
long long st[maxn];
void hash_init(){
    memset(head,0,sizeof(head));
}

int hash(long long p,int prime=10000019){
    int h;
    //hash操作
    h=p%prime;
    return h;
}

bool add_hash(int s){
    int h=hash(st[s]);
    int u=head[h];
    while(u){
        //if (memcmp(st[u],st[s],sizeof(st[s]))==0) return 0;
        //if (strcmp(st[u],st[s])==0) return 0;
        if (st[u]==st[s]) return 0;
        u=next[u];
    }
    next[s]=head[h];
    head[h]=s;
    return 1;
}

bool search_hash(long long p){
    int h=hash(p);
    int u=head[h];
    while (u){
        //if (memcmp(st[u],p,sizeof(st[u]))==0) return 1;
        //if (strcmp(st[u],str)==0) return 1;
        if (st[u]==p) return 1;
        u=next[u];
    }
    return 0;
}

---

1.2 树hash

---

从某个常数开始,每次乘以 p,和一个元素异或,再除以 q 取余,再乘以 p,和下一个元素异或,除以 q 取余.....

一直进行到最后一个元素为止。最后把所得到的结果乘以 b,再对 q 取余。

---

    hash[u]=977872;
    for(i=0;i<son[u];i++)
    {
        for(j=i;j<son[u]&&q[i].hash==q[j].hash;j++)
        {
            hash[u]*=P;
            hash[u]^=q[j].hash;
            hash[u]%=mod;
        }
        j--;
        ans[u]*=cal(q[i].ans+j-i,j-i+1);
        ans[u]%=mod;
        i=j;
    }


---

2 各种最长子序列

---

void LXS(int* a,int* f,int n)
{
    vector<int>d;
    int l,r;
    REP(i,n)
    {
        //l=lower_bound(d.begin(),d.end(),a[i])-d.begin();
        r=upper_bound(d.begin(),d.end(),a[i])-d.begin();
        if (r==sz(d)) d.push_back(a[i]);
        else d[r]=a[i];
        f[i]=r+1;
    }
}

---------------


---------------


---------------


---------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值