【模板】模板合计【未完】


高精度加法

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
int a[1000], b[1000], c[1000]; 
char s[1000]; 
int main() { 
    int i, j, k, m, n; 
    int alen, blen, clen; 
    gets(s); 
    alen = strlen(s); 
    for (i = alen - 1; i >= 0; i--) 
        a[alen - i] = s[i] - '0'; 
    gets(s); 
    blen = strlen(s); 
    for (i = blen - 1; i >= 0; i--) 
        b[blen - i] = s[i] - '0'; 
    clen = alen > blen ? alen : blen; 
    for (i = 1; i <= clen; i++) 
        c[i] = a[i] + b[i]; 
    for (i = 1; i < clen; i++) 
        if (c[i] >= 10) { 
            c[i + 1]++; 
            c[i] -= 10; 
        } 
    for (i = clen; i >= 1; i--) 
        printf("%d", c[i]); 
    puts(""); 
    system("pause"); 
    return 0; 
}

高精度减法

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
int a[1000], b[1000], c[1000]; 
char s[1000]; 

int main() { 
    int i, j, k, m, n; 
    int alen, blen, clen; 
    gets(s); 
    alen = strlen(s); 
    for (i = alen - 1; i >= 0; i--) 
        a[alen - i] = s[i] - '0'; 
    gets(s); 
    blen = strlen(s); 
    for (i = blen - 1; i >= 0; i--) 
        b[blen - i] = s[i] - '0'; 
    for (i = 1; i <= alen; i++) 
        c[i] = a[i] - b[i]; 
    for (i = 1; i < alen; i++) 
        if (c[i] < 0) { 
            c[i + 1]--; 
            c[i] += 10; 
        } 
    while (c[alen] == 0 && alen != 1) 
        alen--; 
    for (i = alen; i >= 1; i--) 
        printf("%d", c[i]); 
    puts(""); 
    system("pause"); 
    return 0; 
}

高精度乘法

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 

int a[1000], b[1000], c[2000]; 
char s[1000]; 
int main() { 
    int i, j, k, m, n; 
    int alen, blen, clen; 
    gets(s); 
    alen = strlen(s); 
    for (i = alen - 1; i >= 0; i--) 
        a[alen - i] = s[i] - '0'; 
    gets(s); 
    blen = strlen(s); 

    for (i = blen - 1; i >= 0; i--) 
        b[blen - i] = s[i] - '0'; 
    for (i = 1; i <= alen; i++) 
        for (j = 1; j <= blen; j++) 
            c[i + j - 1] += a[i] * b[j]; 
    for (i = 1; i < alen + blen - 1; i++) 
        if (c[i] >= 10) { 
            c[i + 1] += c[i] / 10; 
            c[i] %= 10; 
        } 
    for (i = alen + blen - 1; i >= 1; i--) 
        printf("%d", c[i]); 
    puts(""); 
    system("pause"); 
    return 0; 
}

高精度除法

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
int a[1000], c[2000]; 
char s[1000], tmp; 
int main() { 
    int i, j, k, m, n; 
    int alen, clen; 
    gets(s); 
    alen = strlen(s); 
    for (i = 0; i < alen; i++) a[i + 1] = s[i] - '0'; 
    /*tmp=getchar();*/ 
    scanf("%d", &m); 
    k = a[1]; i = 1; 
    while (k < m)  
    { 
        i++;  
        k = k * 10 + a[i]; 
    } 
    clen = 0; 
    c[++clen] = k / m; 
    k %= m; 
    i++; 
    for (; i <= alen; i++)  
    { 
        k = k * 10 + a[i]; 
        c[++clen] = k / m; 
        k %= m; 
    } 
    puts("结果是:"); 
    for (i = 1; i <= clen; i++) printf("%d", c[i]); 
    if (k > 0) printf("
余数是:%d
", k); 
    puts(""); 
    system("pause"); 
    return 0; 
}

归并排序

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#include<cmath> 
using namespace std; 
int n; 
int a[1000005], r[100005]; 
inline int read() { 
    int x = 0, w = 1; char ch = 0; 
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); 
    if (ch == '-') w = -1, ch = getchar(); 
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - 48, ch = getchar(); 
    return x * w; 
} 
void msort(int s, int t) { 
    if (s == t) return; 
    int m = (s + t) >> 1; 
    msort(s, m); 
    msort(m + 1, t); 
    int i = s, j = m + 1, k = s; 
    while (i <= m && j <= t) 
        if (a[i] < a[j]) r[k++] = a[i++]; 
        else r[k++] = a[j++]; 
    while (i <= m) r[k++] = a[i++]; 
    while (j <= t) r[k++] = a[j++]; 
    for (int i = s; i <= t; i++) a[i] = r[i]; 
} 
int main() { 
    n = read(); 
    for (int i = 1; i <= n; i++) a[i] = read(); 
    msort(1, n); 
    for (int i = 1; i <= n; i++) printf("%d ", a[i]); 
}

快速排序

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#include<cmath> 
#include<ctime> 
using namespace std; 
int n,a[100005]; 
inline int read(){ 
    int x=0,w=1;char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); 
    return x*w; 
} 
void qsort(int l,int r){ 
    int i=l,j=r; 
    int t=(rand()%(r-l+1))+l; 
    int m=a[t]; 
    do{ 
        while(a[i]<m) i++; 
        while(a[j]>m) j--; 
        if(i<=j){ 
            swap(a[i],a[j]); 
            i++,j--; 
        } 
    }while(i<=j); 
    if(i<r) qsort(i,r); 
    if(j>l) qsort(l,j);  
} 
int main(){ 
    srand(time(0)); 
    n=read(); 
    for(int i=1;i<=n;i++) a[i]=read(); 
    qsort(1,n);  
    for(int i=1;i<=n;i++) printf("%d ",a[i]); 
}

堆排序

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<cmath> 
#include<algorithm> 
using namespace std; 
int n,a[1000005],tot; 
inline int read(){ 
    int x=0,w=1;char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); 
    return x*w; 
} 
inline void up(int num,int max){ 
    int j=num>>1; 
    while(j){ 
        if(a[j]>a[num]){ 
            swap(a[j],a[num]); 
            num=j;j=num>>1; 
        } 
        else return; 
    } 
} 
inline void down(int num,int max){ 
    int j=num<<1; 
    while(j<=max){ 
        if(a[j]>a[j+1]&&j<max) j++; 
        if(a[j]<a[num]){ 
            swap(a[j],a[num]); 
            num=j;j=num<<1; 
        } 
        else j=max+1; 
    } 
} 
int main(){ 
    int n=read(); 
    for(int i=1;i<=n;i++) { 
        int x=read(); 
         a[++tot]=x;up(tot,tot); 
    } 
    for(int i=tot;i>=2;i--){ 
        swap(a[i],a[1]); 
        down(1,i-1); 
    } 
    for(int i=n;i>=1;i--) printf("%d ",a[i]); 
}

最小生成树

prime

using namespace std; 
int map[5050][5050]; 
int n,m,sum; 
int dis[5005],vis[5005]; 
inline int read() { 
    int w=1,x=0; char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar(); 
    return x*w; 
} 
void Prim() { 
    memset(vis,0,sizeof(vis)); 
    for(int i=1; i<=n; i++) dis[i]=map[1][i]; 
    vis[1]=1; 
    int pos; 
    for(register int i=1; i<=n-1; ++i) { 
        int minn=0x3f3f3f3f; 
        for(register int j=1; j<=n; ++j) { 
            if(!vis[j]&&dis[j]<minn) minn=dis[j],pos=j; 
        } 
        vis[pos]=1;sum+=dis[pos]; 
        for(register int j=1; j<=n; ++j) { 
            if(!vis[j]&&dis[j]>map[pos][j]) 
                dis[j]=min(dis[j],map[pos][j]); 
        } 
    } 
} 
int main() { 
    n=read();m=read(); 
    for(register int i=1; i<=n; i++) 
        for(register int j=1; j<=n; j++) 
            if(i==j) map[i][j]=0; 
            else map[i][j]=0x3f3f3f3f; 
    for(register int i=1; i<=m; i++) { 
        int t1=read(),t2=read(),t3=read(); 
        map[t1][t2]=map[t2][t1]=min(map[t1][t2],t3); 
    } 
    Prim(); 
    printf("%d
",sum); 
    return 0; 
}

kruskal

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#include<cmath> 
using namespace std; 
struct arr{ 
    int u,v,c; 
}w[200010]; 
int n,m,ans; 
int f[5010]; 
inline int read(){ 
    int x=0,w=1;char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); 
    return x*w; 
}  
inline int cmp(arr a,arr b){ return a.c<b.c; } 
int gf(int x){ return f[x]==x?x:f[x]=gf(f[x]); } 
void union1(int u,int v,int c){ 
    int f1=gf(u),f2=gf(v); 
    if(f1!=f2){ 
        f[f1]=f2; 
        ans+=c; 
    } 
} 
int main(){ 
    n=read();m=read(); 
    for(int i=1;i<=n;i++) f[i]=i; 
    for(int i=1;i<=m;i++) w[i].u=read(),w[i].v=read(),w[i].c=read(); 
    sort(1+w,1+w+m,cmp); 
    for(int i=1;i<=m;i++)  
     union1(w[i].u,w[i].v,w[i].c); 
    printf("%d",ans); 
    return 0; 
}

次小生成树

线段树

(常数稍大版)区间修改,区间查询一段和,区间查询最大值

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#include<cmath> 
using namespace std; 
typedef long long ll; 
struct arr{ 
    int l,r,tag;ll sum; 
}tree[500000]; 
int n,m,i,u; 
inline int read(){ 
    int x=0,w=1;char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar(); 
    return x*w; 
} 
void build(ll p,ll l,ll r){ 
    tree[p].l=l;tree[p].r=r; 
    if(l!=r) { 
        int m=(l+r)>>1; 
        build(p<<1,l,m); 
        build((p<<1)+1,m+1,r); 
    } 
} 
inline void push_down(ll p){ 
    if(tree[p].tag==0) return ; 
    tree[p<<1].sum+=tree[p].tag*(tree[p<<1].r-tree[p<<1].l+1); 
    tree[(p<<1)+1].sum+=tree[p].tag*(tree[(p<<1)+1].r-tree[(p<<1)+1].l+1); 
    tree[p<<1].tag+=tree[p].tag; 
    tree[(p<<1)+1].tag+=tree[p].tag; 
    tree[p].tag=0; 
} 
void change(ll p,ll l,ll r,ll data){ 
    if(tree[p].l==l&&tree[p].r==r) { 
        tree[p].sum+=(r-l+1)*data;tree[p].tag+=data; return; 
    } 
    push_down(p); 
    int m=(tree[p].l+tree[p].r)>>1; 
    if(r<=m) change(p<<1,l,r,data); 
    else if(l>m) change((p<<1)+1,l,r,data); 
         else change(p<<1,l,m,data),change((p<<1)+1,m+1,r,data); 
    tree[p].sum=tree[p<<1].sum+tree[(p<<1)+1].sum; 
} 
ll getsum(ll p,ll l,ll r){ 
    if(tree[p].l==l&&tree[p].r==r) return tree[p].sum; 
    push_down(p); 
    int m=(tree[p].l+tree[p].r)>>1; 
    if(r<=m) return getsum(p<<1,l,r); 
    else if(l>m) return getsum((p<<1)+1,l,r); 
         else  return getsum(p<<1,l,m)+getsum((p<<1)+1,m+1,r); 
} 
int main(){ 
    n=read();m=read(); 
    build(1,1,n); 
    for(register int i=1;i<=n;i++) { int x=read();change(1,i,i,x); } 
    for(register int i=1;i<=m;i++){ 
        int u=read(); 
        if(u==1) { int x=read(),y=read(),k=read();change(1,x,y,k); } 
        if(u==2) { int x=read(),y=read();printf("%lld
",getsum(1,x,y));  } 
    } 
}

树状数组(差分优化)

#include<iostream> 
#include<cstdio> 
using namespace std; 
int n,m; 
int c[500005],BIT[500005]; 
inline int read(){ 
    int x=0,w=1;char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar(); 
    return x*w; 
} 

int lowbit(int x){ return x&-x; } 
void add(int pos,int k) 
{ while(pos<=n){ BIT[pos]+=k; pos+=lowbit(pos); } } 
int sum(int pos) 
{ int ans=0; while(pos){ ans+=BIT[pos]; pos-=lowbit(pos); } return ans; } 

int main(){ 
  n=read();m=read(); 
  for (int i=1;i<=n;i++){ c[i]=read(); add(i,c[i]-c[i-1]); } 
  for (int i=1;i<=m;i++){ 
      int num,x,y,k; 
      num=read();x=read(); 
      if(num==1){y=read();k=read();add(x,k);add(y+1,-k);} 
      if(num==2) printf("%d
",sum(x)); 
     } 
}

Splay

Splay(区间翻转版)

#include<cstdio> 
#include<algorithm> 
using namespace std; 
const int N=101000; 
int ch[N][2]; 
int size[N],rev[N],fa[N]; 
int n,m,rt=0; 
int read(){ 
    int x=0,f=1;char ch=getchar(); 
    while (ch<'0' || ch>'9'){if (ch=='-')f=-1;ch=getchar();} 
    while ('0'<=ch && ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 
    return x*f; 
} 
void pushup(int x){ 
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1; 
} 
void pushdown(int x){ 
    if (rev[x]){ 
        int &lc=ch[x][0],&rc=ch[x][1]; 
        swap(lc,rc); 
        rev[lc]^=1;rev[rc]^=1;rev[x]=0; 
    } 
} 
void build(int l,int r,int &rt){ 
    if (l>r) return; 
    int mid=(l+r)>>1; 
    if (mid<rt)ch[rt][0]=mid;else ch[rt][1]=mid; 
    fa[mid]=rt;size[mid]=1; 
    if (l==r)return; 
    build(l,mid-1,mid);build(mid+1,r,mid); 
    pushup(mid); 
} 
void rotate(int x,int &k){ 
    int y=fa[x],z=fa[y],d=ch[y][1]==x; 
    if (y==k)k=x; 
    else ch[z][ch[z][1]==y]=x; 
    fa[ch[x][d^1]]=y;fa[y]=x;fa[x]=z; 
    ch[y][d]=ch[x][d^1];ch[x][d^1]=y; 
    pushup(x);pushup(y); 
} 
void splay(int x,int &k){ 
    while (x!=k){ 
        int y=fa[x],z=fa[y]; 
        if (y!=k){ 
            if ((ch[z][0]==y)^(ch[y][0]==x))rotate(x,k); 
                else rotate(y,k); 
        } 
        rotate(x,k); 
    } 
} 
int select(int &rt,int k){ 
    pushdown(rt); 
    int sum=size[ch[rt][0]]+1; 
    if (sum==k)return rt; 
    if (sum>k)return select(ch[rt][0],k); 
        else return select(ch[rt][1],k-sum); 
} 
void rever(int L,int R){ 
    splay(L,rt);splay(R,ch[L][1]); 
    rev[ch[R][0]]^=1; 
} 
void print(int rt){ 
    pushdown(rt); 
    if (ch[rt][0])print(ch[rt][0]); 
    if (2<=rt && rt<=n+1)printf("%d ",rt-1); 
    if (ch[rt][1])print(ch[rt][1]); 
} 
int main(){ 
    n=read(),m=read(); 
rt=(3+n)>>1;build(1,n+2,rt); 
/*将询问区间[l,r]转换成[l+1,r+1],那么我们翻转l-1,r+1时就不需要特判了。*/ 
    for (int i=1;i<=m;i++){ 
        int L=read(),R=read(); 
        L=select(rt,L);R=select(rt,R+2); 
        rever(L,R); 
    } 
    print(rt); 
    return 0; 
}

Splay(常用版)

Struct Tree { 
      int key, size, fa, son[2]; 
} 
void PushUp(int x); 
void Rotate(int x, int p); /*0左旋 1右旋*/ 
void Splay(int x, int To) /*将x节点插入到To的子节点中*/ 
int find(int key) /*返回值为key的节点 若无返回0 若有将其转移到根处*/ 
int prev() /*返回比根值小的最大值 若无返回0 若有将其转移到根处*/ 
int succ() /*返回比根值大的最小值 若无返回0 若有将其转移到根处*/ 
void Insert(int key) /*插入key 并且将该节点转移到根处*/ 
void Delete(int key) /*删除值为key的节点 若有重点只删其中一个 x的前驱移动到根处*/ 
int GetPth(int p) /*获得第p小的节点 并将其转移到根处*/ 
int GetRank(int key) /*获得值<=key的节点个数 并将其转移到根处 若<key只需将<=换为<*/ 
int cnt=1, rt=0; 
struct Tree { 
    int key, size, fa, son[2]; 
    void set(int _key, int _size, int _fa) { 
        key=_key; 
        size=_size; 
        fa=_fa; 
        son[0]=son[1]=0; 
    } 
} T[MAXN]; 

inline void PushUp(int x) { 
    T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+1; 
} 

inline void Rotate(int x, int p) { /*0左旋 1右旋*/ 
    int y=T[x].fa; 
    T[y].son[!p]=T[x].son[p]; 
    T[T[x].son[p]].fa=y; 
    T[x].fa=T[y].fa; 
    if(T[x].fa) 
        T[T[x].fa].son[T[T[x].fa].son[1] == y]=x; 
    T[x].son[p]=y; 
    T[y].fa=x; 
    PushUp(y); 
    PushUp(x); 
} 

void Splay(int x, int To) { /*将x节点插入到To的子节点中*/ 
    while(T[x].fa != To) { 
        if(T[T[x].fa].fa == To) 
            Rotate(x, T[T[x].fa].son[0] == x); 
        else { 
            int y=T[x].fa, z=T[y].fa; 
            int p=(T[z].son[0] == y); 
            if(T[y].son[p] == x) 
                Rotate(x, !p), Rotate(x, p); /*之字旋*/ 
            else 
                Rotate(y, p), Rotate(x, p); /*一字旋*/ 
        } 
    } 
    if(To == 0) rt=x; 
} 

int find(int key) { /*返回值为key的节点 若无返回0 若有将其转移到根处*/ 
    int x=rt; 
    while(x && T[x].key != key) 
        x=T[x].son[key > T[x].key]; 
    if(x) Splay(x, 0); 
    return x; 
} 

int prev() { /*返回比根值小的最大值 若无返回0 若有将其转移到根处*/ 
    int x=T[rt].son[0]; 
    if(!x) return 0; 
    while(T[x].son[1]) 
        x=T[x].son[1]; 
    Splay(x, 0); 
    return x; 
} 

int succ() { /*返回比根值大的最小值 若无返回0 若有将其转移到根处*/ 
    int x=T[rt].son[1]; 
    if(!x) return 0; 
    while(T[x].son[0]) 
        x=T[x].son[0]; 
    Splay(x, 0); 
    return x; 
} 

void Insert(int key) { /*插入key 并且将该节点转移到根处*/ 
    if(!rt) 
        T[rt = cnt++].set(key, 1, 0); 
    else { 
        int x=rt, y=0; 
        while(x) { 
            y=x; 
            x=T[x].son[key > T[x].key]; 
        } 
        T[x = cnt++].set(key, 1, y); 
        T[y].son[key > T[y].key]=x; 
        Splay(x, 0); 
    } 
} 

void Delete(int key) { /*删除值为key的节点 若有重点只删其中一个 x的前驱移动到根处*/ 
    int x=find(key); 
    if(!x) return; 
    int y=T[x].son[0]; 
    while(T[y].son[1]) 
        y=T[y].son[1]; 
    int z=T[x].son[1]; 
    while(T[z].son[0]) 
        z=T[z].son[0]; 
    if(!y && !z) { 
        rt=0; 
        return; 
    } 
    if(!y) { 
        Splay(z, 0); 
        T[z].son[0]=0; 
        PushUp(z); 
        return; 
    } 
    if(!z) { 
        Splay(y, 0); 
        T[y].son[1]=0; 
        PushUp(y); 
        return; 
    } 
    Splay(y, 0); 
    Splay(z, y); 
    T[z].son[0]=0; 
    PushUp(z); 
    PushUp(y); 
} 

int GetPth(int p) { /*获得第p小的节点 并将其转移到根处*/ 
    if(!rt) return 0; 
    int x=rt, ret=0; 
    while(x) { 
        if(p == T[T[x].son[0]].size+1) 
            break; 
        if(p>T[T[x].son[0]].size+1) { 
            p-=T[T[x].son[0]].size+1; 
            x=T[x].son[1]; 
        } else 
            x=T[x].son[0]; 
    } 
    Splay(x, 0); 
    return x; 
} 
int GetRank(int key) { /*获得值<=key的节点个数 并将其转移到根处 若<key只需将<=换为<*/ 
    if(!rt) return 0; 
    int x=rt, ret=0, y; 
    while(x) { 
        y=x; 
        if(T[x].key <= key) { 
            ret+=T[T[x].son[0]].size+1; 
            x=T[x].son[1]; 
        } else 
            x=T[x].son[0]; 
    } 
    Splay(y, 0); 
    return ret; 
}

Splay(完全版)

Struct Tree { 
      int key, num, size, fa, son[2]; 
} 
void PushUp(int x); 
void PushDown(int x); 
int Newnode(int key, int fa); /*新建一个节点并返回*/ 
void Rotate(int x, int p); /*0左旋 1右旋*/ 
void Splay(int x, int To); /*将x节点移动到To的子节点中*/ 
int GetPth(int p, int To); /*返回第p小的节点 并移动到To的子节点中*/ 
int Find(int key); /*返回值为key的节点 若无返回0 若有将其转移到根处*/ 
int Prev(); /*返回根节点的前驱*/ 
int Succ(); /*返回根结点的后继*/ 
void Insert(int key); /*插入key值*/ 
void Delete(int key); /*删除值为key的节点*/ 
int GetRank(int key); /*获得值<=key的节点个数*/ 
void Delete(int l, int r); /*删除值在[l, r]中的节点*/ 
int cnt, rt; 
int Add[MAXN]; 

struct Tree { 
    int key, num, size, fa, son[2]; 
} T[MAXN]; 

inline void PushUp(int x) { 
    T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+T[x].num; 
} 

inline void PushDown(int x) { 
    if(Add[x]) { 
        if(T[x].son[0]) { 
            T[T[x].son[0]].key+=Add[x]; 
            Add[T[x].son[0]]+=Add[x]; 
        } 
        if(T[x].son[1]) { 
            T[T[x].son[1]].key+=Add[x]; 
            Add[T[x].son[1]]+=Add[x]; 
        } 
        Add[x]=0; 
    } 
} 

inline int Newnode(int key, int fa) { /*新建一个节点并返回*/ 
    ++cnt; 
    T[cnt].key=key; 
    T[cnt].num=T[cnt].size=1; 
    T[cnt].fa=fa; 
    T[cnt].son[0]=T[cnt].son[1]=0; 
    return cnt; 
} 
inline void Rotate(int x, int p) { /*左旋 1右旋*/ 
    int y=T[x].fa; 
    PushDown(y); 
    PushDown(x); 
    T[y].son[!p]=T[x].son[p]; 
    T[T[x].son[p]].fa=y; 
    T[x].fa=T[y].fa; 
    if(T[x].fa) 
        T[T[x].fa].son[T[T[x].fa].son[1] == y]=x; 
    T[x].son[p]=y; 
    T[y].fa=x; 
    PushUp(y); 
    PushUp(x); 
} 
void Splay(int x, int To) { /*将x节点移动到To的子节点中*/ 
    while(T[x].fa != To) { 
        if(T[T[x].fa].fa == To) 
            Rotate(x, T[T[x].fa].son[0] == x); 
        else { 
            int y=T[x].fa, z=T[y].fa; 
            int p=(T[z].son[0] == y); 
            if(T[y].son[p] == x) 
                Rotate(x, !p), Rotate(x, p); /*之字旋*/ 
            else 
                Rotate(y, p), Rotate(x, p); /*一字旋*/ 
        } 
    } 
    if(To == 0) rt=x; 
} 
int GetPth(int p, int To) { /*返回第p小的节点 并移动到To的子节点中*/ 
    if(!rt || p > T[rt].size) return 0; 
    int x=rt; 
    while(x) { 
        PushDown(x); 
        if(p >= T[T[x].son[0]].size+1 && p <= T[T[x].son[0]].size+T[x].num) 
            break; 
        if(p > T[T[x].son[0]].size+T[x].num) { 
            p-=T[T[x].son[0]].size+T[x].num; 
            x=T[x].son[1]; 
        } else 
            x=T[x].son[0]; 
    } 
    Splay(x, 0); 
    return x; 
} 
int Find(int key) { /*返回值为key的节点 若无返回0 若有将其转移到根处*/ 
    if(!rt) return 0; 
    int x=rt; 
    while(x) { 
        PushDown(x); 
        if(T[x].key == key) break; 
        x=T[x].son[key > T[x].key]; 
    } 
    if(x) Splay(x, 0); 
    return x; 
} 
int Prev() { /*返回根节点的前驱 非重点*/ 
    if(!rt || !T[rt].son[0]) return 0; 
    int x=T[rt].son[0]; 
    while(T[x].son[1]) { 
        PushDown(x); 
        x=T[x].son[1]; 
    } 
    Splay(x, 0); 
    return x; 
} 
int Succ() { /*返回根结点的后继 非重点*/ 
    if(!rt || !T[rt].son[1]) return 0; 
    int x=T[rt].son[1]; 
    while(T[x].son[0]) { 
        PushDown(x); 
        x=T[x].son[0]; 
    } 
    Splay(x, 0); 
    return x; 
} 
void Insert(int key) { /*插入key值*/ 
    if(!rt) 
        rt=Newnode(key, 0); 
    else { 
        int x=rt, y=0; 
        while(x) { 
            PushDown(x); 
            y=x; 
            if(T[x].key == key) { 
                T[x].num++; 
                T[x].size++; 
                break; 
            } 
            T[x].size++; 
            x=T[x].son[key > T[x].key]; 
        } 
        if(!x) 
            x=T[y].son[key > T[y].key]=Newnode(key, y); 
        Splay(x, 0); 
    } 
} 
void Delete(int key) { /*删除值为key的节点1个*/ 
    int x=Find(key); 
    if(!x) return; 
    if(T[x].num>1) { 
        T[x].num--; 
        PushUp(x); 
        return; 
    } 
    int y=T[x].son[0]; 
    while(T[y].son[1]) 
        y=T[y].son[1]; 
    int z=T[x].son[1]; 
    while(T[z].son[0]) 
        z=T[z].son[0]; 
    if(!y && !z) { 
        rt=0; 
        return; 
    } 
    if(!y) { 
        Splay(z, 0); 
        T[z].son[0]=0; 
        PushUp(z); 
        return; 
    } 
    if(!z) { 
        Splay(y, 0); 
        T[y].son[1]=0; 
        PushUp(y); 
        return; 
    } 
    Splay(y, 0); 
    Splay(z, y); 
    T[z].son[0]=0; 
    PushUp(z); 
    PushUp(y); 
} 
int GetRank(int key) { /*获得值<=key的节点个数*/ 
    if(!Find(key)) { 
        Insert(key); 
        int tmp=T[T[rt].son[0]].size; 
        Delete(key); 
        return tmp; 
    } else 
        return T[T[rt].son[0]].size+T[rt].num; 
} 
void Delete(int l, int r) { /*删除值在[l, r]中的所有节点 l!=r*/ 
    if(!Find(l)) Insert(l); 
    int p=Prev(); 
    if(!Find(r)) Insert(r); 
    int q=Succ(); 
    if(!p && !q) { 
        rt=0; 
        return; 
    } 
    if(!p) { 
        T[rt].son[0]=0; 
        PushUp(rt); 
        return; 
    } 
    if(!q) { 
        Splay(p, 0); 
        T[rt].son[1]=0; 
        PushUp(rt); 
        return; 
    } 
    Splay(p, q); 
    T[p].son[1]=0; 
    PushUp(p); 
    PushUp(q); 
}

树链剖分

树链剖分POJ 模板题

第一个操作:将第i条边的权值变为v。
第二个操作:将点a到点b路径上的边权变为其相反数。
第三个操作:查询点a到点b路径上的边权最大值。

#include<iostream> 
#include<cstdio> 
#include<algorithm> 
#include<cmath> 
#include<cstring> 
#define ls p<<1 
#define rs (p<<1)+1 
#define mid (tree[p].l+(tree[p].r-tree[p].l)/2) 
using namespace std; 
struct Node{ 
    int l,r,p,sum; 
}tree[500005]; 
struct arr{ 
    int nd,nx,co,id; 
}edge[100005];/*这个地方既可以用邻接链表储存,也可以用动态数组来存 */ 
int head[100005],deep[100005],pos[100005],son_cost[100005]; 
int top[100005],fa[100005],sz[100005],son[100005],road[100005],a[100005]; 
int t,n,cnt,tot,ans; 
int mx[500005],mi[500005],fg[500005]; 
inline void add(int u,int v,int w,int id){ edge[++cnt].nd=v; edge[cnt].co=w; edge[cnt].id=id;edge[cnt].nx=head[u]; head[u]=cnt; } 
inline int read(){ 
    int x=0,w=1;char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); 
    return x*w; 
} 

void dfs1(int u,int father,int depth){/*建立起一棵树,并且查找出重儿子 */ 
    deep[u]=depth;fa[u]=father;sz[u]=1; 
    for(int i=head[u];i;i=edge[i].nx){ 
        int v=edge[i].nd; 
        if(v!=father){ 
            road[edge[i].id]=v; 
            dfs1(v,u,depth+1); 
            sz[u]+=sz[v]; 
            if(son[u]==-1||sz[son[u]]<sz[v]) { 
                son[u]=v; 
/*              son_cost[u]=edge[i].co;*/ 
            } 
        }/*这一步很重要!!!第二个if是为了记录重儿子是哪一个 */ 
    } 
} 
void dfs2(int u,int tp,int cost){/*这个操作是将重轻链的最顶端的点求出来 */ 
    top[u]=tp;pos[u]=++tot;a[tot]=cost; 
    if(son[u]==-1) return; 
    dfs2(son[u],tp,son_cost[u]); 
    for(int i=head[u];i;i=edge[i].nx){ 
        int v=edge[i].nd; 
        if(v!=fa[u]&&v!=son[u]) dfs2(v,v,edge[i].co); 
    } 
}  

inline void pushup(int p){  mx[p]=max(mx[ls],mx[rs]); mi[p]=min(mi[ls],mi[rs]);  } 
inline void push_down(int p){ 
    if(fg[p]){ 
        fg[ls]^=1; fg[rs]^=1; 
        int tmp=mx[ls]; mx[ls]=-mi[ls]; mi[ls]=-tmp; 
        tmp=mx[rs]; mx[rs]= -mi[rs]; mi[rs]= -tmp;  
        fg[p]=0; 
    } 
} 
void build(int l,int r,int p){ 
    tree[p].l=l; tree[p].r=r; 
    if(l==r) { 
        mx[p]=a[l]; 
        mi[p]=a[l]; 
        return; 
    } 
    int midd=(l+r)>>1; 
    build(l,midd,ls); 
    build(midd+1,r,rs); 
    pushup(p); 
} 
void change(int p,int l,int data){ 
    if (tree[p].l==tree[p].r){ 
        mi[p]=mx[p]=data; 
    } else { 
        push_down(p); 
        if (l<=mid) change(ls,l,data); 
        else change(rs,l,data); 
        pushup(p); 
    } 
} 
void nega(int p,int l,int r){ 
    if(l<=tree[p].l&&tree[p].r<=r){ 
        fg[p]^=1;  
        int tmp=mx[p]; 
        mx[p]=-mi[p]; 
        mi[p]=-tmp; 
        return; 
    } 
    push_down(p); 
    if(l<=mid) nega(ls,l,r); 
    if(r>mid) nega(rs,l,r); 
    pushup(p); 
} 
void NEGATE(int x,int y,int n){ 
    while(top[x]!=top[y]){ 
        if(deep[top[x]]<deep[top[y]]) swap(x,y); 
        nega(1,pos[top[x]],pos[x]); 
        x=fa[top[x]]; 
    } 
    if(x==y) return; 
    if(deep[x]>deep[y]) swap(x,y); 
    nega(1,pos[son[x]],pos[y]); 
} 

int query(int p,int l,int r){ 
    if(l<=tree[p].l&&tree[p].r<=r) return mx[p]; 
    push_down(p); 
    int ans = -(1<<30); 
    if(l<=mid) ans=max(ans,query(ls,l,r)); 
    if(r>mid) ans=max(ans,query(rs,l,r)); 
    pushup(p); 
    return ans; 
} 

int QUERY(int x,int y,int n){ 
    if(x==y) return 0; 
    int ans=-(1<<30); 
    while(top[x]!=top[y]){ 
        if(deep[top[x]]<deep[top[y]]) swap(x,y); 
        ans=max(ans,query(1,pos[top[x]],pos[x])); 
        x=fa[top[x]]; 
    } 
    if(x==y) return ans; 
    if(deep[x]>deep[y]) swap(x,y); 
    ans=max(ans,query(1,pos[son[x]],pos[y])); 
    return ans; 
}  
void init(){ 
    tot=cnt=0; 
    memset(head,0,sizeof(head)); 
    memset(son,-1,sizeof(head)); 
    memset(fg,0,sizeof(fg)); 
} 
int main(){ 
    t=read(); 
    for(int k=1;k<=t;k++){ 
        n=read();init(); 
        for(int i=1;i<=n-1;i++){ 
            int u=read(),v=read(),w=read();  
            add(u,v,w,i);add(v,u,w,i); 
        } 
        dfs1(1,0,0);  
        dfs2(1,1,0);  
        build(2,n,1); 
        char ch[10]; 
        while(~scanf("%s",ch)){ 
            if(*ch=='D') break; 
            int u=read(),v=read(); 
            if(*ch=='Q')printf("%d
",QUERY(u,v,n)); 
            else if(*ch=='C') change(1,pos[road[u]],v); 
            else NEGATE(u,v,n); 
        } 
    } 
}

树链剖分 洛谷模板题 维护点权

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#include<cmath> 
#include<vector> 
#define ls (rt<<1) 
#define rs (rt<<1|1) 
#define mid (tree[rt].l+(tree[rt].r-tree[rt].l)/2) 
using namespace std; 
struct arr{ 
    int l,r,sum,tag; 
}tree[3000000]; 
int w[200000],id[200000],deep[200000],fa[200000],sz[200000]; 
int top[200000],son[200000],pos[200000]; 
int n,m,rr,MD,cnt; 
vector<int>g[2000000]; 
template<typename tp>void read(tp & dig){/*读入优化*/  
    char c=getchar();dig=0; 
    while(!isdigit(c))c=getchar(); 
    while(isdigit(c))dig=dig*10+c-'0',c=getchar(); 
} 
inline int read(){ 
    int x=0,w=1;char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar(); 
    return x*w; 
} 
inline void pushup(int rt){tree[rt].sum=tree[ls].sum+tree[rs].sum;} 
inline void build(int l,int r,int rt){/*建立一棵线段树 */ 
    tree[rt].l=l,tree[rt].r=r; 
    if(l==r){tree[rt].sum=w[id[l]];return ;} 
    int midd=l+(r-l)/2; 
    build(l,midd,ls),build(midd+1,r,rs); 
    pushup(rt); 
} 
inline void pushdown(int rt){/*下传标记 */ 
    if(tree[rt].tag){ 
        tree[ls].tag=(tree[ls].tag+tree[rt].tag)%MD; 
        tree[rs].tag=(tree[rs].tag+tree[rt].tag)%MD; 
        tree[ls].sum=(tree[ls].sum+(tree[ls].r-tree[ls].l+1)*tree[rt].tag)%MD; 
        tree[rs].sum=(tree[rs].sum+(tree[rs].r-tree[rs].l+1)*tree[rt].tag)%MD; 
        tree[rt].tag=0; 
    } 
} 

inline void update(int l,int r,int c,int rt){/*区间、单点修改 */ 
    if(l<=tree[rt].l&&tree[rt].r<=r){   /*线段树的另一种写法,快一些 */ 
        tree[rt].sum=(tree[rt].sum+(c*(tree[rt].r-tree[rt].l+1)%MD))%MD; 
        tree[rt].tag+=c%MD; 
        return ; 
    } 
    pushdown(rt); 
    if(l<=mid) update(l,r,c,ls);/*为啥是这样写? */ 
    if(r>mid) update(l,r,c,rs); 
    pushup(rt); 
} 

inline long long query(int l,int r,int rt){/*区间查询 */ 
    if(l<=tree[rt].l&&tree[rt].r<=r) return tree[rt].sum; 
    pushdown(rt); 
    int ans=0; 
    if(l<=mid) ans+=query(l,r,ls),ans%=MD; 
    if(r>mid) ans+=query(l,r,rs),ans%=MD; 
    return ans%MD; 
} 
void dfs1(int x,int fat,int dep){ 
    deep[x]=dep,fa[x]=fat,sz[x]=1; 
    for(int i=0;i<g[x].size();i++){ 
        int v=g[x][i]; 
        if(v!=fat){ 
            dfs1(v,x,dep+1); 
            sz[x]+=sz[v]; 
            if(son[x]==-1||sz[son[x]]<sz[v]) son[x]=v; 
        } 
    } 
} 
void dfs2(int x,int tp){ 
    top[x]=tp;pos[x]=++cnt;id[pos[x]]=x; 
    if(son[x]==-1) return; 
    dfs2(son[x],tp); 
    for(int i=0;i<g[x].size();i++){ 
        int v=g[x][i]; 
        if(v!=fa[x]&&v!=son[x]) dfs2(v,v); 
    } 
} 
long long add(int t1,int t2,int data,int ok){ 
    long long u=t1,v=t2,ans=0; 
    while(top[u]!=top[v]){ 
        if(deep[top[u]]>deep[top[v]]) swap(u,v); 
        if(!ok)update(pos[top[v]],pos[v],data,1); 
        else ans+=query(pos[top[v]],pos[v],1),ans%=MD; 
        v=fa[top[v]]; 
    } 
    if(deep[u]>deep[v]) swap(u,v); 
    if(!ok) update(pos[u],pos[v],data,1); 
    else ans+=query(pos[u],pos[v],1); 
    return ans%=MD; 
} 
int main(){ 
    memset(son,-1,sizeof(son)); 
    n=read();m=read();rr=read();MD=read(); 
    for(int i=1;i<=n;i++) w[i]=read(); 
    for(int i=1;i<=n-1;i++){ 
        int u=read(),v=read(); g[u].push_back(v);g[v].push_back(u); 
    } 
    dfs1(rr,-1,1); 
    dfs2(rr,rr); 
    build(1,n,1);/*建树*/ 
    for(int i=1;i<=m;i++){ 
        int xx,t1,t2,t3; 
        cin>>xx; 
        if(xx==1) t1=read(),t2=read(),t3=read(),add(t1,t2,t3,0);  
        if(xx==3) t1=read(),t2=read(),update(pos[t1],pos[t1]+sz[t1]-1,t2,1); 
        if(xx==2) t1=read(),t2=read(),printf("%lld
",add(t1,t2,0,1)%MD); 
        if(xx==4) t2=read(),printf("%lld
",query(pos[t2],pos[t2]+sz[t2]-1,1)%MD); 
    } 
    return 0; 
}

树的重心

#include <iostream> 
#include <string.h> 
#include <algorithm> 
#include <stdio.h> 
using namespace std; 
const int N = 50005; 
const int INF = 1<<30; 
int head[N],int son[N], cnt,n,ans[N],num,size; 
bool vis[N]; 
struct Edge { 
    int to; 
    int next; 
}; 

Edge edge[2*N]; 


void Init() { 
    cnt = 0; num = 0; 
    size = INF; 
    memset(vis,0,sizeof(vis)); 
    memset(head,-1,sizeof(head)); 
} 
void add(int u,int v) { edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } 
void dfs(int cur) { 
    vis[cur] = 1; 
    son[cur] = 0; 
    int tmp = 0; 
    for(int i=head[cur]; ~i; i=edge[i].next) { 
        int u = edge[i].to; 
        if(!vis[u]) { 
            dfs(u); 
            son[cur] += son[u] + 1; 
            tmp = max(tmp,son[u] + 1); 
        } 
    } 
    tmp = max(tmp,n-son[cur]-1); 
    if(tmp < size) { 
        num = 1; 
        ans[0] = cur; 
        size = tmp; 
    } else if(tmp == size) { ans[num++] = cur; } 
} 
int main() { 
    while(~scanf("%d",&n)) { 
        Init(); 
        for(int i=1; i<=n-1; i++) { 
            int u,v; 
            scanf("%d%d",&u,&v); 
            add(u,v); add(v,u); 
        } 
        dfs(1); 
        sort(ans,ans+num); 
        for(int i=0; i<num; i++) printf("%d ",ans[i]); 
        puts(""); 
    } 
    return 0; 
}

树的直径

 1 #include<cstdio>
 2 #include<cstring>
 3 #define N 4200
 4 struct hehe{
 5     int next;
 6     int to;
 7 }edge[N];
 8 int num_edge,head[N],dis[N],n,a,b,pos;
 9 int add_edge(int from,int to){
10     edge[++num_edge].next=head[from];
11     edge[num_edge].to=to;
12     head[from]=num_edge;
13 }
14 int dfs(int x){
15     for(int i=head[x];i;i=edge[i].next)
16         if(!dis[edge[i].to]){
17             dis[edge[i].to]=dis[x]+1;
18             dfs(edge[i].to);
19         }
20 }
21 int main(){
22     scanf("%d",&n);
23     for(int i=1;i<n;++i){
24         scanf("%d%d",&a,&b);
25         add_edge(a,b);
26         add_edge(b,a);
27     }
28     dfs(1);
29     for(int i=pos=1;i<=n;i++) if(dis[i]>dis[pos]) pos=i;
30     memset(dis,0,sizeof(dis));
31     dfs(pos);
32     for(int i=pos=1;i<=n;i++) if(dis[i]>dis[pos]) pos=i;
33     printf("%d
",dis[pos]);
34     return 0;
35 }
View Code

并查集

找爸爸1——递归:

int gf(int x) { 
    if(x==f[x]) return x; 
    else return f[x]=gf(f[x]); 
} 
或者也可以这样  
int gf(int x) { return x==f[x]?x:f[x]=gf(f[x]); }

找爸爸2——非递归:

int gf(int x) { 
    int u=x; 
    int v; 
    while(x!=f[x]) x=f[x]; 
    while(f[u]!=x) { 
        v=f[u]; 
        f[u]=x; 
        u=v; 
    } 
    return x; 
}

找爸爸3-—朴素:

int gfa(int x)  { return  fa[x]==x? x:gf(fa[x]); }

合并1——朴素(配合找爸爸1和2使用):

void union1(int u,int v)  { 
    int fa=gf(u) , fb=gf(v) ; 
    if(fa!=fb)  f[fa]=fb; 
}

合并2——按秩合并(配合找爸爸3使用):

void  union1 (int u,int v) { 
    int fa=gf(u),fb=gf(v); 
    if  (fa!=fb) { 
        if(dep[fa]>dep[fb])  swap(fa,fb); 
        f[fa]=fb; 
        if  (dep[fa]==dep[fb])  dep[fa]++; 
    } 
}

最近公共祖先(LCA)

Tarjan版本

#include<cstdio> 
#include<iostream> 
#include<cstring> 
#include<algorithm> 
#define maxn 1000010 
using namespace std; 
int n,m,s,cnt,tot; 
struct arr { 
    int nd,nx,num; 
} bot[maxn],bot_ask[maxn]; /*用邻接链表存边*/ 
int head[maxn],head_ask[maxn]; 
int fa[maxn],ans[maxn],vis[maxn]; 
void add_edge(int x,int y) { /*这里是把题目中给的关系放在一个邻接链表中*/ 
    bot[++cnt].nd=y; 
    bot[cnt].nx=head[x]; 
    head[x]=cnt; 
} 
void add_ask(int x,int y,int num) { /*这里是把题目所给的询问存在另一个邻接链表中*/ 
    bot_ask[++tot].nd=y; 
    bot_ask[tot].nx=head_ask[x]; 
    bot_ask[tot].num=num; 
    head_ask[x]=tot; 
} 
int gf(int x) { 
    return fa[x]==x?x:fa[x]=gf(fa[x]);   /*找爸爸*/ 
} 
void dfs(int u) { 
    vis[u]=1;/*记录是否被搜索过*/ 
    for(int i=head_ask[u]; i; i=bot_ask[i].nx) 
      if(vis[bot_ask[i].nd])ans[bot_ask[i].num]=gf(bot_ask[i].nd); 
    /*如果该点的询问对象被访问过,那吗他们的最近公共最先就是询问对象的祖先*/ 
    for(int i=head[u]; i; i=bot[i].nx)   
      if(!vis[bot[i].nd])  dfs(bot[i].nd),fa[bot[i].nd]=u; 
    /*如果该节点没有被搜索过,继续递归下去。回溯的时候将爸爸修改一下*/ 
} 
inline int read(){ 
    int x=0,w=1; char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); 
    return x*w; 
} 
int main() { 
    int x,y; 
    n=read(); 
    m=read(); 
    s=read();/*利用读入优化来读取数据会更快点*/ 
    for(int i=1; i<=n; i++) fa[i]=i; /*初始父亲为自己*/ 
    for(int i=1; i<=n-1; i++) { 
        x=read(),y=read(),add_edge(x,y),add_edge(y,x); 
    } 
    for(int i=1; i<=m; i++) { 
        x=read(),y=read(),add_ask(x,y,i),add_ask(y,x,i); 
    } 
    dfs(s); 
    for(int i=1; i<=m; i++) printf("%d
",ans[i]); 
    return 0; 
}

倍增版本

using namespace std; 
struct arr{ 
    int u,nd,nx; 
}bot[1000001]; 
int head[1000001],deep[1000001],fa[1000001][20]; 
int n,m,s,mm,stepp,cnt; 
void add(int x,int y)  
{ bot[++cnt].u=x; bot[cnt].nd=y; bot[cnt].nx=head[x]; head[x]=cnt; }//用邻接链表存边  
void build_tree(int u){ 
    for(int i=head[u];i;i=bot[i].nx){ 
        int v=bot[i].nd; 
        if(deep[v]==0){ 
            deep[v]=deep[u]+1; mm=max(mm,deep[v]+1); 
            fa[v][0]=u; 
            build_tree(v); 
        } 
    } 
} 
inline void init(){ 
    for(int j=1;j<=stepp;j++) 
     for(int i=1;i<=n;i++) 
      fa[i][j]=fa[fa[i][j-1]][j-1]; 
} 
int LCA(int x,int y){ 
    if(deep[x]<deep[y]) swap(x,y); 
    for(int k=stepp;k>=0;k--){ 
        if(deep[fa[x][k]]>=deep[y]) 
        x=fa[x][k]; 
    } 
    if(x==y) return y; 
    for(int i=stepp;i>=0;i--) 
     if(fa[x][i]!=fa[y][i]) 
      x=fa[x][i],y=fa[y][i]; 
    return fa[x][0]; 
} 
inline int read(){ 
    int x=0,w=1; char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); 
    return x*w; 
} 
int main(){ 
    n=read();m=read();s=read(); 
    for(int i=1;i<=n-1;i++){ 
        int u=read(),v=read(); 
        add(u,v),add(v,u); 
    } 
    deep[s]=1; 
    build_tree(s); 
    stepp=log2(mm); 
    init(); 
    for(int i=1;i<=m;i++){ 
        int u=read(),v=read(); 
        printf("%d
",LCA(u,v)); 
    } 
    return 0; 
}

最短路

省略了最基本的几种算法

SPFA(路径条数)

/*简单的加分原理是不好搞定的,因为可能会重复累加。 
于是乎,考虑定义两个数组F[x],Sf[x]分别表示到X点能传递的最短路方案数,到x点的最短路方案数。 
那么很显然: 
bf[a] 为true表示在队列中*/ 
if dis[a]=dis[b]+w<a,b> then 
 begin 
  if bf[a] then  
   F[a]:=F[a]+F[b]/*在队列中的话,那么其能传递的方案数并没有累加给其他点,所以要留着*/ 
 else F[a]:=F[b];/*不在队列中的话,那么他之前能传递方案数已经累加给其他点了,那么就直接覆盖,将能传递的方案数直接赋值。*/ 
 Sf[a]:=Sf[a]+F[b];/*对于a这个点的答案,要累加上b能传递的方案数。*/ 
 end 
if dis[a]>dis[b]+w<a,b> then 
 begin 
   dis[a]:=dis[b]+w<a,b> 
   F[a]:=F[b]; 
  Sf[a]:=Sf[b];  
 end;

Floyd判最小环

#include <iostream> 
#include <cstdio> 
#include <algorithm> 
#include <cstring> 
using namespace std; 
const int INF=1e8; 
int w[102][102],g[102][102]; 
int n,e; 
void init() { 
    int x,y,v; 
    for(int i=1; i<=n; i++) 
        for(int j=1; j<=n; j++) 
            w[i][j]=g[i][j]=INF; 
    for(int i=1; i<=e; i++) { 
        scanf("%d%d%d",&x,&y,&v); 
        w[x][y]=w[y][x]=g[x][y]=g[y][x]=v; 
    } 
} 
void work() { 
    int ans=INF; 
    for(int k=1; k<=n; k++) { 
        for(int i=1; i<k; i++) /*最小环*/ 
            for(int j=i+1; j<k; j++) /*为了避免一条边计算两次并且i == j时因为权重会出错*/ 
                ans=min(ans,g[i][j]+w[i][k]+w[k][j]); 
        for(int i=1; i<=n; i++) /*Floyd*/ 
            for(int j=1; j<=n; j++) 
                if(i!=j) 
                    g[i][j]=min(g[i][j],g[i][k]+g[k][j]); 
    } 
    if(ans==INF) cout<<"No solution."<<endl; 
    else cout<<ans<<endl; 
} 
int main() { 
    while(scanf("%d%d",&n,&e)!=EOF) { 
        init(); 
        work(); 
    } 
}

强连通分量

tarjan

/*Tarjan*/ 
const int N =1010, M=100010; 
struct node { 
    int to, next; 
} edge[M]; 
int head[N], low[N], dfn[N], sta[N], belg[N], num[N]; 
bool vis[N]; 
int scc,index,top, tot; 
void tarbfs(int u) { 
    int i,j,k,v; 
    low[u]=dfn[u]=++index; 
    sta[top++]=u; 
    vis[u]=1; 
    for(i=head[u]; i!=-1; i=edge[i].next) { 
        v=edge[i].to; 
        if(!dfn[v]) { 
            tarbfs(v); 
            if(low[u]>low[v]) low[u]=low[v]; 
        } else if(vis[v]&&low[u]>dfn[v]) low[u]=dfn[v]; 
    } 
    if(dfn[u]==low[u]) { 
        scc++; 
        do { 
            v=sta[--top]; 
            vis[v]=0; 
            belg[v]=scc; 
            num[scc]++; 
        } while(v!=u) ; 
    } 
} 
void Tarjan(int n) { 
    memset(vis,0,sizeof(vis)); 
    memset(dfn,0,sizeof(dfn)); 
    memset(num,0,sizeof(num)); 
    memset(low,0,sizeof(low)); 
    index=scc=top=0; 
    for(int i=1; i<=n; i++) 
        if(!dfn[i]) tarbfs(i); 
} 
void init() { 
    tot=0; 
    memset(head,-1,sizeof(head)); 
} 
void addedge(int i,int j) { 
    edge[tot].to=j; 
    edge[tot].next=head[i]; 
    head[i]=tot++; 
}

拓扑排序(以洛谷旅行计划为例题)

#include<iostream> 
#include<cstdio> 
#include<algorithm> 
#include<cmath> 
#include<cstring> 
#include<queue> 
using namespace std; 
struct arr{ 
    int nd,nx; 
}bot[300000]; 
queue<int>q; 
int n,m,tot,cnt,head[200000],top[200000],f[200000],rd[200000]; 
inline int read(){ 
    int w=1,x=0;char ch=0; 
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 
    if(ch=='-') w=-1,ch=getchar(); 
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar(); 
    return x*w; 
} 
inline void add(int a,int b){ bot[++tot].nd=b; bot[tot].nx=head[a]; head[a]=tot; } 
int main(){ 
    n=read();m=read(); 
    for(register int i=1;i<=m;++i){ 
        int u=read(),v=read(); 
        add(u,v);rd[v]++; 
    } 
    for(register int i=1;i<=n;++i) 
        if(!rd[i]) q.push(i); 
    while(!q.empty()){ 
        top[++cnt]=q.front();q.pop(); 
        for(register int i=head[top[cnt]];i;i=bot[i].nx){ 
            rd[bot[i].nd]--; 
            if(!rd[bot[i].nd]) q.push(bot[i].nd); 
        } 
    } 
    for(register int k=1;k<=cnt;++k){ 
        if(!f[top[k]]) 
         f[top[k]]=1; 
        for(register int i=head[top[k]];i;i=bot[i].nx) 
         if(f[top[k]]+1>f[bot[i].nd]) 
          f[bot[i].nd]=f[top[k]]+1; 
    } 
    for(register int i=1;i<=n;++i) 
     printf("%d
",f[i]); 
}

欧拉线性筛

int main(){ 
    int n,m,tot=0; 
    scanf("%d%d",&n,&m); 
    memset(point,0,sizeof point); 
    point[0]=point[1]=1; 
    for (int i=2;i<=n;i++){ 
        if (point[i]==0)  
         prime[tot++]=i; 
        for (int j=0;j<tot;j++){ 
            if (i*prime[j]>n) break; 
            point[i*prime[j]]=1; 
            if (i % prime[j]==0) break; 
        } 
     } 
    for (int i=1;i<=m;i++){ 
        int a; 
        scanf("%d",&a); 
        if (point[a]==0) printf("Yes
"); 
        else printf("No
"); 
     } 
}

快速幂+多项式系数

#include<iostream> 
#include<cstring> 
#include<algorithm> 
#include<cstdio> 
#include<cmath> 
using namespace std; 
int n,m,k,a,b; 
int C[1005][1005];  
inline int mi(int a,int b){ 
    long long w=a,s=1; 
    for(;b;b>>=1){ 
        if(b&1) s=(s*w)%10007; 
        w=(w*w)%10007; 
    } 
    return s; 
} 
int main(){ 
    scanf("%d%d%d%d%d",&a,&b,&k,&n,&m); 
    C[0][0]=1; 
    for(int i=1;i<=k;i++) C[i][0]=1,C[i][i]=1; 
    for(int i=1;i<=k;i++) 
     for(int j=1;j<i;j++) 
      C[i][j]=(C[i-1][j]+C[i-1][j-1])%10007; 
    printf("%d",((C[k][m]*mi(a,n)%10007)*mi(b,m))%10007); 
    return 0; 
}

RMQ

using namespace std; 
int a[50001],dp[50001][20]; /*a是原数组,dp是动归数组*/ 
int n; 
inline int maxn(int a,int b) {return a>b?a:b;} 
/*两种方法处理DP数组*/ 
/*方法一:dp数组存最大值*/ 
void ST1() { 
    for(int i=1; i<=n; i++) dp[i][0]=a[i];/*初始化*/ 
    for(int j=1; (1<<j)<=n; j++) {/*dp[i][j]表示从第i位开始,往后第(2^j)-1位*/ 
        for(int i=1; i+(1<<j)-1<=n; i++) {/*范围不能超过长度n  
            dp[i][j]=maxn(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);*/ 
/*因为是二分,所以尽可能地把当前这一段给覆盖掉*/ 
/*一个是从第i位往后2^j-1位,这里为一半,另一半是从第i+j^2开始,往后2^j-1,可以刚好覆盖掉 */ 
        } 
    } 
} 
int rmq1(int l,int r) { 
    int j=0; 
    while((1<<(j+1))<=r-l+1) j++;/*查询的时候,尽可能地使j变大能够刚好使j^2的长度能够覆盖这段区间 */ 
    return maxn(dp[l][j],dp[r-(1<<j)+1][j]);/*左边一半,右边一半qu最值 */ 
} 
/*方法二:dp数组存最大值的编号*/ 
void ST2(int n) { 
    for(int i=1; i<=n; i++)/*存最大编号的稍微改一下 */ 
        dp[i][0] = i; 
    for(int j=1; (1<<j)<=n; j++) { 
        for(int i=1; i+(1<<j)-1<=n; i++) { 
            int x = dp[i][j-1] , y = dp[i+(1<<(j-1))][j-1]; 
            dp[i][j] = a[x]<a[y]?x:y; 
        } 
    } 
} 
int rmq2(int l,int r) { 
    int j=0; 
    while((1<<(j+1))<=r-l+1) j++; 
    int x=dp[l][j] , y=dp[r-(1<<j)+1][j]; 
    return maxn(a[x],a[y]); 
}

KMP

#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#include <iostream> 
#include <string> 
using namespace std; 
int f[15000]; 
void getfill(string s)  { 
    memset(f,0,sizeof(f));  /*根据其前一个字母得到*/ 
    for(int i=1; i<s.size(); i++)  { 
        int j=f[i]; 
        while(j && s[i]!=s[j]) j=f[j]; 
        f[i+1]=(s[i]==s[j])?j+1:0; 
    } 
} 
int find(string a,string s)  { 
    int ans=0; 
    getfill(s); 
    int j=0; 
    for(int i=0; i<a.size(); i++)  { 
        while(j && a[i]!=s[j]) j=f[j]; 
        if(a[i]==s[j]) j++; 
        if(j==s.size()) { ans++; } 
    } 
    return ans; 
} 
int main()  { 
    string s,a; 
    int T; 
    scanf("%d",&T); 
    while(T--)  { 
        getchar(); 
        cin>>s>>a; 
        int ans=find(a,s); 
        printf("%d
",ans); 
    } 
    return 0; 
} 
/* 
void getFail(char* P,int* f){ 
    int m=strlen(P); 
    f[0]=f[1]=0; 
    for(int i=1;i<m;i++){ 
        int j=f[i]; 
        while(j&&P[i]!=P[j]) j=f[j]; 
        f[i+1]=P[i]==P[j]?j+1:0; 
    } 
} 
void Find(char* T,char* P,int* f){ 
    int n=strlen(T),m=strlen(P); 
    getFail(P,f); 
    int j=0; 
    for(int i=0;i<n;i++){ 
        while(j&&P[j]!=T[i]) j=f[j]; 
        if(P[j]==T[i]) j++; 
        if(j==m) printf("%d
",i-m+1); 
    } 
} 
*/

Trie树

指针

int n, m; 
struct NODE { 
    int cnt; NODE *next[26]; 
    NODE() { 
        cnt = 0; 
        memset(next, NULL, sizeof(next)); 
    } 
}; 
char s[15]; 
void Insert(NODE *root, char *s) { 
    int len = strlen(s); 
    NODE *p = root; 
    for(int i = 0; i < len; i++) { 
        int idx = s[i] - 'a'; 
        if(p -> next[idx] == NULL) p -> next[idx] = new NODE(); 
        p = p -> next[idx]; p -> cnt ++; 
    } 
} 
int Search(NODE *root, char *s) { 
    int len = strlen(s); 
    NODE *p = root; 
    for(int i = 0; i < len; i++) { 
        int idx = s[i] - 'a'; 
        if(i != len && p -> next[idx] == NULL) return 0; 
        p = p -> next[idx]; 
    } 
    return p -> cnt; 
} 
int main() { 
    scanf("%d", &n);{ 
        NODE *root = new NODE(); 
        for(int i = 0; i < n; i++) { 
            scanf("%s", s); 
            Insert(root, s); 
        } 
        scanf("%d", &m); 
        while(m --) { 
            scanf("%s", s); 
            printf("%d
", Search(root, s)); 
        } 
    } 
}

Trie(数组)

int const MAX = 2600005; 
int n, m; 
char s[15]; 
struct Trie { 
    int next[MAX][26], cnt[MAX], tot, root; 
    inline int Newnode() { 
        memset(next[tot], -1, sizeof(next[tot])); 
        return tot ++; 
    } 
    inline void Init() { 
        memset(cnt, 0, sizeof(cnt)); 
        tot = 0; root = Newnode(); 
    } 
    inline void Insert(char *s) { 
        int len = strlen(s); 
        int p = root; 
        for(int i = 0; i < len; i++) { 
            int idx = s[i] - 'a'; 
            if(next[p][idx] == -1) next[p][idx] = Newnode(); 
            p = next[p][idx]; cnt[p] ++; 
        } 
    } 
    inline int Search(char *s) { 
        int len = strlen(s); int p = root; 
        for(int i = 0; i < len; i++) { 
            int idx = s[i] - 'a'; 
            if(i != len && next[p][idx] == -1) return 0; 
            p = next[p][idx]; 
        } 
        return cnt[p]; 
    } 
} t;  
int main() { 
    while(scanf("%d", &n) != EOF) { 
        t.Init(); 
        for(int i = 0; i < n; i++) { scanf("%s", s); t.Insert(s); } 
        scanf("%d", &m); 
        while(m --) { 
            scanf("%s", s); printf("%d
", t.Search(s)); 
        } 
    } 
}
原文地址:https://www.cnblogs.com/bbqub/p/template.html