1. 程式人生 > >ACM模板(完善中......)

ACM模板(完善中......)

ACM模板

.圖論

3.最小生成樹(prim)

.動態規劃

四.資料結構之各種樹

3.Splay(伸展樹)

圖論

  1. 最短路徑Dijkstra + 優先佇列優化 + 陣列模擬鄰接表

#include <iostream>

   #include <cstdio>

#include <cstring>

#include <queue>

using namespace std;

typedef long long ll;

const int maxn = 500010;

int n, m, top, head[maxn];

int dist[maxn];

bool vis[maxn];

struct Edge{

  int v, w;

  int next;

}edge[maxn * 2];

struct node{

  int id;

  int dis;

   bool operator<(const node &a)const{

        return dis > a.dis;

    }

};

 void add(int u, int v, int w)

{

   edge[top].v = v;

   edge[top].w = w;

   edge[top].next = head[u];

   head[u] = top++;

}

 void Dijkstra()

{

   node s;

   priority_queue < node > q;

   memset(vis, false, sizeof(vis));

   memset(dist, 125, sizeof(dist));

   dist[1] = 0;

   s.id = 1;

   s.dis = 0;

   q.push(s);

   while(!q.empty())

   {

       int index = q.top().id;

       q.pop();

       vis[index] = true;

       for(int i = head[index]; i != -1; i = edge[i].next)

       {

            int v = edge[i].v;

    int w = edge[i].w;

    if(vis[v])

      continue;

           if(dist[v] > dist[index] + w)

       {

              dist[v] = dist[index] + w;

              s.id = v;

              s.dis = dist[v];

              q.push(s);

       }

       }

   }

}

int main()

{

//freopen("in.txt", "r", stdin);

   scanf("%d%d", &n, &m);

top = 0;

memset(head, -1, sizeof(head));

int  u, v, w;

for(int i = 1; i <= m; ++ i)

{

      scanf("%d%d%d", &u, &v, &w);

          add(u, v, w);

          add(v, u, w);

}

Dijkstra();

printf("%d\n", dist[n]);

   return 0;

}

#include <iostream>

#include <cstdio>

#include <cstring>

#include <stack>

#include <queue>

#include <algorithm>

#define INF 0x3f3f3f3f

using namespace std;

const int N = 50002;

int n, m, top;

int head[N], dist[N], vis[N];

struct node{

    int v, w;

    int next;

}edge[N * 3];

void add(int u, int v, int w)

{

    edge[top].v = v;

    edge[top].w = w;

    edge[top].next = head[u];

    head[u] = top++;

}

void spfa()

{

    for(int i = 1; i <= n; i++)

    {

        dist[i] = INF;

        vis[i] = 0;

    }

    dist[1] = 0;

    vis[1] = 1;

    stack < int > q;

    q.push(1);

    int ans;

    while(!q.empty())

    {

        ans = q.top();

        q.pop();

        vis[ans] = 0;

        for(int i = head[ans]; i != -1; i = edge[i].next)

        {

            if(dist[edge[i].v] > dist[ans] + edge[i].w)

            {

                dist[edge[i].v] = dist[ans] + edge[i].w;

                if(!vis[edge[i].v])

                {

                    q.push(edge[i].v);

                    vis[edge[i].v] = 1;

                }

            }

        }

    }

}

int main()

{

    //freopen("in.txt", "r", stdin);

    cin >> n >> m;

    top = 0;

    for(int i = 1; i <= n; i++)

    {

        head[i] = -1;

    }

    for(int i = 1; i <= m; i++)

    {

        int a, b, c;

        scanf("%d%d%d", &a, &b, &c);

        add(a, b, c);

    }

    spfa();

    cout << dist[n] << endl;

    return 0;

}

3.最小生成樹(Prim)

/* *  陣列tree[]用來記錄最小生成樹的節點 *  陣列lowdis[]記錄從起點到其餘所有點的距離並不斷更新 *  陣列map[][]記錄所有資料兩點之間的距離 *  point是所有節點的數目,begin是起點 *  mindis是最小生成樹的長度 */ void prime() {     int i,j,min,mindis=0,next;     memset(tree,0,sizeof(tree));     for(i=1;i<=point;i++)     {         lowdis[i]=map[begin][i];//用lowdis[]陣列記錄下從起點到剩下所有點的距離     }     tree[begin]=1;//標記起點(即最小生成樹中的點)     for(i=1;i<point;i++)     {         min=INF;         for(j=1;j<=point;j++)         {             if(!tree[j]&&min>lowdis[j])             {                 min=lowdis[j];//求出從當前起點到其餘所有點的距離中最短的                 next=j;             }         }         mindis+=min;//記錄下整條最小樹的長度         tree[next]=1;         for(j=1;j<=point;j++)         {             if(!tree[j]&&lowdis[j]>map[next][j])             lowdis[j]=map[next][j];//更新lowdis[]陣列         }     }     printf("%d\n",mindis); }

動態規劃

  1. 線性dp
  2. 數位dp

#include <iostream>

#include <cstring>

using namespace std;

int t, k;

int bit[30];

long long dp[20][1 << 10][11];

int get_news(int x, int state)

{

    for(int i = x; i < 10; ++ i)

    {

        if(state & (1 << i))

        {

            return (state ^ (1 << i)) | (1 << x);

        }

    }

    return state | (1 << x);

}

int get_num(int state)

{

    int cnt = 0;

    while(state)

    {

        if(state & 1)

        {

            cnt++;

        }

        state >>= 1;

    }

    return cnt;

}

long long dfs(int pos, int state, bool limits, bool zeros)

{

    if(pos == -1)

        return get_num(state) == k;

    if(!limits && dp[pos][state][k] != -1)

        return dp[pos][state][k];

    int en = limits ? bit[pos] : 9;

    long long ans = 0;

    for(int i = 0; i <= en; ++ i)

    {

        ans += dfs(pos - 1, (zeros && (i == 0)) ? 0 : get_news(i, state), (limits && (i == en)), zeros && (i == 0));

    }

    if(!limits)

    {

        dp[pos][state][k] = ans;

    }

    return  ans;

}

long long solve(long long x)

{

    int len = 0;

    while(x)

    {

        bit[len++] = x % 10;

        x /= 10;

    }

    return dfs(len - 1, 0, true, true);

}

int main()

{

    cin >> t;

    memset(dp, -1, sizeof(dp));

    int ss = 1;

    long long l, r;

    while(t--)

    {

        cin >> l >> r >> k;

        cout << "Case #" << ss++ << ": " << solve(r) - solve(l - 1) << endl;

    }

    return 0;

}

資料結構之各種樹

  1. LCA(Tarjan離線演算法)

#include <iostream>

#include <cstdio>

#include <cstring>

#include <vector>

using namespace std;

/**

1.dfs

2.並査集

3.鄰接表(vector、陣列模擬)

*/

vector < int > Tree[10009];

vector < int > query[10009];

int t, n;

bool vis[10009];

int root[10009];

int ans[10009];   

/**

用一個數組存放答案其實是有些不妥,只適用於每次都是不重複的兩個節點的詢問,

如果有一個節點詢問了兩次(例如a,b和a,c)就GG了,需要考慮用其他的形式存放

資料,例如鄰接表。

*/

int pre[10009];

int finds(int x)

{

    if(pre[x] == x)

        return x;

    int t = finds(pre[x]);

    return pre[x] = t;

}

void dfs(int u)

{

    for(int i = 0; i < (int)Tree[u].size(); ++ i)

    {

        dfs(Tree[u][i]);

        pre[Tree[u][i]] = u;   ///合併

    }

    vis[u] = true;    ///標記為已訪問

    for(int i = 0; i < (int)query[u].size(); ++ i)   

    {

        if(vis[query[u][i]])

        {

            int x = finds(query[u][i]);

            ans[u] = x;

            ans[query[u][i]] = x;

        }

    }

}

int main()

{

    //freopen("in.txt", "r", stdin);

    cin >> t;

    while(t--)

    {

        cin >> n;

        memset(vis, false, sizeof(vis));

        memset(root, 0, sizeof(root));

        memset(ans, 0, sizeof(ans));

        for(int i = 1; i <= n; ++ i)

        {

            pre[i] = i;

        }

        for(int i = 1; i < n; ++ i)

        {

            int u, v;

            cin >> u >> v;

            Tree[u].push_back(v);

            root[v]++;   ///計算每個節點的入度,最後找到根節點

        }

        int a, b;

        cin >> a >> b;

        query[a].push_back(b);

        query[b].push_back(a);

        for(int i = 1; i <= n; ++ i)

        {

            if(!root[i])   ///如果是根節點的話dfs

            {

                dfs(i);

            }

        }

        cout << ans[a] << endl;

        for(int i = 1; i <= n; ++ i)

        {

            Tree[i].clear();

            query[i].clear();

        }

    }

    return 0;

}

  1. 樹鏈剖分

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int maxn = 2e4+100;

int son[maxn], deep[maxn], father[maxn], num[maxn], top[maxn], p[maxn], fp[maxn], pos;

int Treevalue[maxn];

int first[maxn], ntot;

struct Node

{

    int to, next, val;

} edge[maxn];

struct NODE

{

    int a, b, c;

} input[maxn];

void init()

{

    memset(first, -1, sizeof(first));

    memset(son, -1, sizeof(son));

    pos = ntot = 0;

}

void addedge(int s,int t,int val)

{

    edge[ntot].to=t,edge[ntot].val=val;

    edge[ntot].next=first[s],first[s]=ntot++;

}

///樹鏈剖分

void dfs(int x, int pre,  int de)

{

    deep[x] = de;

    father[x] = pre;

    num[x] = 1;

    for(int i = first[x]; i != -1; i = edge[i].next)

    {

        int to = edge[i].to;

        if(to != pre)

        {

            Treevalue[to] = edge[i].val;

            dfs(to, x, de + 1);

            num[x] += num[to];

            if(son[x] == -1 || num[to] > num[son[x]])

                son[x] = to;

        }

    }

    return ;

}

void getlist(int x, int tp)

{

    top[x] = tp;

    p[x] = pos++;

    fp[p[x]] = x;

    if(son[x] != -1)

        getlist(son[x], tp);

    else

        return ;

    for(int i = first[x]; i != -1; i = edge[i].next)

    {

        int to = edge[i].to;

        if(to != father[x] && to != son[x])

            getlist(to, to);

    }

}

struct TreeNode

{

    int l, r, max;

} tree[maxn * 3];

void push_up(int i)

{

    tree[i].max = max(tree[i << 1].max, tree[i << 1 | 1].max);

}

void build(int i,int l,int r)

{

    tree[i].l=l,tree[i].r=r,tree[i].max=0;

    if(l==r)

    {

        tree[i].max=Treevalue[fp[l]];

        return ;

    }

    int mid=(l+r)>>1;

    build(i<<1,l,mid);

    build(i<<1|1,mid+1,r);

    push_up(i);

}

int Query(int rt,  int L, int R)

{

    if(tree[rt].l >= L && tree[rt].r <= R)

        return tree[rt].max;

    int m = (tree[rt].l + tree[rt].r) >> 1;

    int ans = 0;

    if(L <= m)

        ans = max(ans, Query(rt << 1, L, R));

    if(m < R)

        ans = max(ans, Query(rt << 1 | 1, L, R));

    return ans;

}

void update(int i,int k,int val)//插點

{

    if(tree[i].l == k && tree[i].r == k)

    {

        tree[i].max=val;

        return ;

    }

    int mid=(tree[i].l+tree[i].r)>>1;

    if(k>mid)

        update(i<<1|1,k,val);

    else

        update(i<<1,k,val);

    push_up(i);

}

int getmax(int a, int b)

{

    int res = 0;

    int f1 = top[a], f2 = top[b];

    while(f1 != f2)

    {

        if(deep[f1] < deep[f2])

        {

            swap(f1, f2);

            swap(a, b);

        }

        res = max(res, Query(1, p[f1], p[a]));

        a = father[f1];

        f1 = top[a];

    }

    if(a == b)

        return res;

    if(deep[a] > deep[b])

        swap(a, b);

    return max(res, Query(1, p[son[a]], p[b]));

}

int main()

{

    //freopen("in.txt", "r", stdin);

    int ncase, n;

    cin >> ncase;

    while(ncase--)

    {

        init();

        cin >> n;

        for(int i = 1; i <= n - 1; i++)

        {

            scanf("%d%d%d",&input[i].a,&input[i].b,&input[i].c);

            addedge(input[i].a,input[i].b,input[i].c);

            addedge(input[i].b,input[i].a,input[i].c);

        }

        dfs(1, 0, 0);

        getlist(1,1);

        build(1, 1, n -1 );

        while(1)

        {

            char op[10];

            scanf("%s", op);

            if(op[0] == 'D')

                break;

            if(op[0] == 'C')

            {

                int a, b;

                scanf("%d%d", &a, &b);

                int aa = input[a].a, bb = input[a].b;

                if(deep[aa] < deep[bb])

                    swap(aa, bb);

                update(1, p[aa], b);

            }

            else

            {

                int a, b;

                scanf("%d%d", &a, &b);

                printf("%d\n", getmax(a, b));

            }

        }

    }

    return 0;

}

  1. Splay(伸展樹)

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int INF = 0x3f3f3f3f;

int n;

struct node

{

    int value;

    node *father;

    node *son[2];

    node(int v, node *f)

    {

        value = v;

        father = f;

        son[0] = son[1] = 0;

    }

}*root;

///確定該節點是左孩子還是右孩子,左孩子返回0,右孩子返回1

int Son(node *f, node *t)

{

    return f->son[1] == t;

}

///旋轉

inline void Rotate(node *t)

{

    node *f = t->father;

    node *g = f->father;

    int a = Son(f, t), b = !a;

    f->son[a] = t->son[b];

    if(t->son[b] != NULL)

        t->son[b]->father = f;

    f->father = t;

    t->son[b] = f;

    t->father = g;

    if(g != NULL)

        g->son[Son(g, f)] = t;

    else

        root = t;

}

///伸展操作

inline void Splay(node *t, node *p)

{

    while(t->father != p)

    {

        node *f = t->father;

        node *g = f->father;

        if(g == p)        

            Rotate(t);

        else

        {

            if(Son(g, f) ^ Son(f, t))

            {

                Rotate(t);

                Rotate(t);

            }

            else

            {

                Rotate(f);

                Rotate(t);

            }

        }

    }

}

///插入操作

inline int Insert(int val)          ///如果樹中已經存在val返回0,否則插入並返回1

{

    if(root == NULL)

    {

        root = new node(val, NULL);

        return 1;

    }

    node *t = root;

    node *f = NULL;

    while(t)

    {

        if(t->value == val)

        {

            return 0;

        }

        f = t;

        t = t->son[val >= t->value];

    }

    f->son[val >= f->value] = new node(val, f);

    Splay(f->son[val >= f->value], NULL);

    return 1;

}

///刪除操作

inline void Delete(int val) 

{

    node *t = root;

    while(t)                ///先找到該節點的位置

    {

        if(t->value == val)

            break;

        t = t->son[val > t->value];

    }

    if(t != NULL)

    {

        Splay(t, NULL);

        if(t->son[0] == NULL)

        {

            root = t->son[1];

            if(root != NULL)

                root->father = NULL;

        }

        else

        {

            node *tmp = root->son[0];

            while(tmp->son[1])

            {

                tmp = tmp->son[1];

            }

            Splay(tmp, t);

            root = tmp;

            root->father = NULL;

            root->son[1] = t->son[1];

            if(root->son[1] != NULL)

                root->son[1]->father = tmp;

        }

    }

}