ACM模板(完善中......)
ACM模板
一.圖論
3.最小生成樹(prim)
二.動態規劃
四.資料結構之各種樹
3.Splay(伸展樹)
圖論
- 最短路徑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); }
動態規劃
- 線性dp
- 數位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;
}
資料結構之各種樹
- 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;
}
- 樹鏈剖分
#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;
}
- 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;
}
}
}