板子1
Dijkstra:
int cnt, head[maxn]; ll dis[maxn];
struct Edge {
int v, next; ll w; //记住这里改顺序下面push进队一定要改!
bool operator < (const Edge &rhs) const {
return w > rhs.w;
}
} e[maxn*4];
void add(int u, int v, ll co) {
e[cnt].v = v;
e[cnt].w = co;
e[cnt].next = head[u];
head[u] = cnt++;
}
void init() {
cnt = 0;
memset(head, -1, sizeof(head));
}
void dij(int s, int len) {
priority_queue<Edge> pq;
for (int i = 1; i <= len; i++)
dis[i] = inf;
bool vis[maxn] = {0};
dis[s] = 0;
pq.push((Edge){s, 0, 0});
while (!pq.empty()) {
Edge tmp = pq.top(); pq.pop();
if (vis[tmp.v]) continue;
vis[tmp.v] = 1;
for (int i = head[tmp.v]; ~i; i = e[i].next) {
Edge u = e[i];
if (dis[u.v] > dis[tmp.v] + u.w) {
dis[u.v] = dis[tmp.v] + u.w;
pq.push((Edge){u.v, 0, dis[u.v]});
}
}
}
}
组合数打表:
void init() {
for (int i = 0; i < maxn; i++) {
for (int j = 0; j <= i; j++) {
if (j == 0) c[i][j] = 1;
else
c[i][j] = (c[i-1][j] + c[i-1][j-1]) % mod; // C[i][j]表示i里面挑选j个
}
}
}
LIS
int d[maxn], a[maxn];
void LIS() {
vector<int> v;
for (int i = 1; i <= n; i++) {
int si = v.size();
int p = lower_bound(v.begin(), v.end(), a[i]) - v.begin(); //lower是严格 upper是不严格
if (p == si) v.push_back(a[i]);
else {
v[p] = a[i];
}
d[i] = p + 1;
}
}
LCA(ST表):
vector<int> G[maxn];
int ver[maxn*2], dp[maxn*2][33], tot, R[maxn*2], vis[maxn], first[maxn];
int n;
void dfs(int x, int dep) {
vis[x] = 1, ver[++tot] = x; R[tot] = dep; first[x] = tot;
for (int i = 0; i < G[x].size(); i++) {
int u = G[x][i];
if (vis[u]) continue;
dfs(u, dep+1);
ver[++tot] = x; R[tot] = dep;
}
}
void RMQ_init(int len) {
for (int i = 1; i <= len; i++) dp[i][0] = i;
for (int j = 1; (1<<j) <= len; j++) {
for (int i = 1; i + (1 << j) - 1 <= len; i++) {
int a = dp[i][j-1], b = dp[i+(1<<(j-1))][j-1];
dp[i][j] = R[a] < R[b] ? a : b;
}
}
}
int RMQ(int l, int r) {
int k = 0;
while ((1 << (k+1)) <= r-l+1) k++;
int a = dp[l][k], b = dp[r-(1<<k)+1][k];
return R[a] < R[b] ? a : b;
}
int LCA(int u, int v) {
int x = first[u], y = first[v];
if (x > y) swap(x, y);
return ver[RMQ(x, y)];
}
void init() {
tot = 0;
for (int i = 1; i <= n; i++) G[i].clear();
memset(vis, 0, sizeof(vis));
}
void solve() {
int m;
cin >> n >> m;
init();
for (int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v);
}
dfs(1, 1);
RMQ_init(tot);
for (int i = 1; i <= m; i++) {
int u, v; scanf("%d%d", &u, &v);
int x = LCA(u, v);
cout << x << endl;
}
}
二分图判定 + 最大匹配(邻接表初识)
int n, m, head[maxn], cnt, col[maxn], link[maxn];
struct Edge {
int to, next;
} e[maxn*maxn];
void add(int u, int v) {
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
void init() {
cnt = 0;
memset(head, -1, sizeof(head));
memset(col, -1, sizeof(col));
}
bool color(int u) {
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (col[v] == -1) {
col[v] = !col[u];
if (!color(v)) return false;
}
else if (col[v] == col[u]) return false;
}
return true;
}
bool dfs(int u) {
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (col[v]) continue;
col[v] = 1;
if (link[v] == -1 || dfs(link[v])) {
link[v] = u;
return true;
}
}
return false;
}
int match() {
int ans = 0;
memset(link, -1, sizeof(link));
for (int i = 1; i <= n; i++) {
memset(col, 0, sizeof(col));
if (dfs(i)) ans++;
}
return ans;
}
void solve() {
while (cin >> n >> m) {
init();
for (int i = 1; i <= m; i++) {
int u, v; scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
int flag = 1;
for (int i = 1; i <= n; i++) {
if (col[i] == -1) {
col[i] = 1;
if (!color(i)) flag = 0;
}
}
if (!flag) cout << "No\n";
else {
cout << match() / 2 << endl;
}
}
}
搞死小圆
void GAE() {
int ans = 0;
for (int i = 1, l = 1; i <= n && l <= m; i++, l++) { //i是行 l是列
int flag = 0, j;
int tmp = j; db maxx = -inf;
for (int j = i; j <= n; j++) {
if (a[j][l] > maxx) {
tmp = j;
maxx = a[j][l];
}
}
j = tmp;
if (cmp(a[j][l], 0) == 0) {
i--; continue;
}
// ans++;
for (int k = l; k <= m; k++)
swap(a[i][k], a[j][k]);
for (int k = 1; k <= n; k++) {
if (k == i) continue;
db xx = a[k][l] / a[i][l]; //倍数
for (j = l; j <= m; j++) {
a[k][j] -= a[i][j] * xx;
}
}
}
// cout << ans << endl;
}
点双联通分量 + 二分图判定(染色法, poj2942)
int n, m, head[maxn], low[maxn], cnt, col[maxn], pre[maxn];
int ht[maxn][maxn], tim, sta[maxn*maxn], top, ans, can[maxn], kn[maxn];
struct Edge {
int st, to, next, vis;
} e[maxn*maxn*2];
void add(int u, int v) {
e[cnt].st = u;
e[cnt].to = v;
e[cnt].next = head[u];
e[cnt].vis = 0;
head[u] = cnt++;
}
void init() {
tim = cnt = top = ans = 0;
memset(head, -1, sizeof(head));
memset(ht, 0, sizeof(ht));
memset(pre, 0, sizeof(pre));
memset(kn, 0, sizeof(kn));
}
bool color(int u) {
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (!can[v]) continue;
if (col[v] == -1) {
col[v] = !col[u];
if (!color(v)) return false;
}
else if (col[v] == col[u]) return false;
}
return true;
}
void tarjan(int u, int fa) {
pre[u] = low[u] = ++tim;
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (e[i].vis) continue;
e[i].vis = e[i^1].vis = 1;
if (!pre[v]) {
sta[++top] = i;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (low[v] >= pre[u]) {
memset(can, 0, sizeof(can));
int tmp;
do {
tmp = sta[top--];
can[e[tmp].to] = 1;
can[e[tmp].st] = 1;
} while (e[tmp].st != u);
memset(col, -1, sizeof(col));
col[u] = 1;
if (!color(u)) {
for (int j = 1; j <= n; j++)
if (can[j])
kn[j] = 1;
}
}
}
else if (v != fa) { // fa很重要,因为如果是桥的话 就会更新到父节点了
low[u] = min(low[u], pre[v]);
sta[++top] = i;
}
}
}
void solve() {
while (cin >> n >> m) {
if (!n && !m) break;
init();
for (int i = 1; i <= m; i++) {
int u, v; scanf("%d%d", &u, &v);
ht[u][v] = ht[v][u] = 1;
}
for (int i = 1; i <= n; i++)
for (int j = i+1; j <= n; j++)
if (!ht[i][j])
add(i, j), add(j, i);
for (int i = 1; i <= n; i++) {
if (!pre[i]) {
tarjan(i, -1);
}
}
for (int i = 1; i <= n; i++)
if (kn[i]) ans++;
cout << n - ans << endl;
}
}
2维凸包
struct Node {
int x, y, id;
} po[maxn];
int n, l;
int flag;
bool cmp(const Node &a, const Node &b) {
if (a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
int mul(int x1, int x2, int y1, int y2) {
return x1 * y2 - x2 * y1;
}
Node S[maxn];
int top;
void ch(Node cur) {
while (top > flag) {
Node po1 = S[top];
Node po2 = S[top-1];
int x1 = po1.x - po2.x, y1 = po1.y - po2.y;
int x2 = cur.x - po2.x, y2 = cur.y - po2.y;
if (mul(x1, x2, y1, y2) >= 0) {
top--;
}
else break;
}
S[++top] = cur;
}
void solve() {
while (cin >> n >> l) {
for (int i = 1; i <= n; i++) {
scanf("%d%d", &po[i].x, &po[i].y);
po[i].id = i;
}
sort(po+1, po+1+n, cmp);
top = 0;
flag = 1;
for (int i = 1; i <= n; i++) {
ch(po[i]);
}
flag = top;
for (int i = n-1; i >= 1; i--) {
ch(po[i]);
}
top--;
for (int i = 1; i <= top; i++) {
...
}
}
}
LCA(tarjan)
struct Edge{
int v, c;
};
vector<Edge> G[maxn], qur[maxn];
int fa[maxn], dis[maxn], n, ans[205];
bool vis[maxn];
int Find(int x) {
return fa[x] = fa[x] == x ? x : Find(fa[x]);
}
void init() {
for (int i = 1; i <= n; i++) G[i].clear(), qur[i].clear(), fa[i] = i;
dis[1] = 0; memset(vis, 0, sizeof(vis));
}
void Tanjar_LCA(int x) {
vis[x] = 1;
for (int i = 0; i < G[x].size(); i++) {
int hh = G[x][i].c, u = G[x][i].v;
if (vis[u]) continue;
dis[u] = dis[x] + hh;
Tanjar_LCA(u);
fa[u] = Find(x);
}
for (int i = 0; i < qur[x].size(); i++) {
int u = qur[x][i].v;
if (!vis[u]) continue;
int lca = Find(u);
ans[qur[x][i].c] = dis[x] + dis[u] - 2*dis[lca];
}
}
求割顶(tarjan)
int n, low[maxn], pre[maxn], tim, ans;
vector<int> G[maxn];
bool iscut[maxn];
void init() {
ans = 0, tim = 0;
for (int i = 1; i <= n; i++) G[i].clear();
memset(iscut, false, sizeof(iscut));
memset(pre, 0, sizeof(pre));
}
void tarjan(int u, int fa) {
low[u] = pre[u] = ++tim;
int child = 0;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (!pre[v]) {
child++;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (low[v] >= pre[u])
iscut[u] = true;
}
else if (fa != v && pre[v] < pre[u])
low[u] = min(low[u], pre[v]);
}
if (fa < 0 && child == 1)
iscut[u] = false;
}
边双联通分量(tarjan, poj3352)
struct Edge {
int u, v;
} e[maxn<<1];
int n, m, low[maxn], pre[maxn], tim, ebcc_cnt, du[maxn];
vector<int> G[maxn];
int isbri[maxn<<1];
void init() {
ebcc_cnt = tim = 0;
for (int i = 1; i <= n; i++) G[i].clear();
memset(isbri, 0, sizeof(isbri));
memset(pre, 0, sizeof(pre));
memset(du, 0, sizeof(du));
}
void tarjan(int u, int fa) {
low[u] = pre[u] = ++tim;
int child = 0;
for (int i = 0; i < G[u].size(); i++) {
int tmp = G[u][i];
int v = e[tmp].v;
if (!pre[v]) {
child++;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (low[v] > pre[u])
isbri[tmp] = isbri[tmp^1] = true;
}
else if (fa != v) // fa很重要 对于桥
low[u] = min(low[u], pre[v]);
}
}
void dfs(int u) {
pre[u] = ebcc_cnt;
for (int i = 0; i < G[u].size(); i++) {
int tmp = G[u][i];
if (isbri[tmp]) continue;
int v = e[tmp].v;
if (pre[v]) continue;
dfs(v);
}
}
void find_ebcc() {
tarjan(1, -1);
memset(pre, 0, sizeof(pre));
for (int i = 1; i <= n; i++) {
if (!pre[i]) {
ebcc_cnt++;
dfs(i);
}
}
}
void solve() {
while (cin >> n >> m) {
init();
for (int i = 1; i <= m; i++) {
int u, v; scanf("%d%d", &u, &v);
e[i<<1|1].u = u, e[i<<1|1].v = v;
e[i<<1].u = v, e[i<<1].v = u;
G[u].push_back(i<<1|1);
G[v].push_back(i<<1);
}
find_ebcc();
int tot = m<<1|1;
for (int i = 1; i <= n; i++) G[i].clear();
for (int i = 1; i <= tot; i += 2) {
if (isbri[i]) {
int u = e[i].v, v = e[i].u;
du[pre[u]]++, du[pre[v]]++;
}
}
int ans = 0;
for (int i = 1; i <= ebcc_cnt; i++)
if (du[i] == 1) ans++;
if (ebcc_cnt == 1) cout << 0 << endl;
else cout << (ans+1) / 2 << endl;
}
}
线段树(删除了之后的第K个数)
struct TREE{
ll l, r, val;
} tre[maxn*4];
void build(int id, int l, int r) {
tre[id].l = l, tre[id].r = r;
if (l == r) tre[id].val = 1;
else {
int mid = (l+r) >> 1;
build(id<<1, l, mid);
build(id<<1|1, mid+1, r);
tre[id].val = tre[id<<1].val + tre[id<<1|1].val;
}
}
ll query(int id, int pos) {
int tmp;
if (tre[id].l == tre[id].r) {
tre[id].val = 0; return tre[id].l;
}
else {
if (tre[id<<1].val >= pos) tmp = query(id<<1, pos);
else tmp = query(id<<1|1, pos - tre[id<<1].val);
}
tre[id].val = tre[id<<1].val + tre[id<<1|1].val;
return tmp;
}
线段树(单点更新)
struct TREE{
int l, r, m, val;
} tre[maxn*4];
void build(int id, int l, int r) {
tre[id].l = l, tre[id].r = r, tre[id].m = (l + r) >> 1;
if (l == r)
tre[id].val = 1;
else {
int mid = (l+r) >> 1;
build(id<<1, l, mid);
build(id<<1|1, mid+1, r);
// tre[id].val = min(tre[id<<1].val, tre[id<<1|1].val);
}
}
void update(int id, int pos, int val) {
if (tre[id].l == tre[id].r) tre[id].val = val;
else {
int l = tre[id].l, r = tre[id].r;
int mid = (l+r) >> 1;
if (mid >= pos) update(id<<1, pos, val);
else update(id<<1|1, pos, val);
tre[id].val = min(tre[id<<1].val, tre[id<<1|1].val);
}
}
int query(int id, int l, int r) {
if (tre[id].l >= l && tre[id].r <= r) return tre[id].val;
else {
if (r <= tre[id].m) return query(id<<1, l, r);
else if (l > tre[id].m) return query(id<<1|1, l, r);
else return min(query(id<<1, l, tre[id].m), query(id<<1|1, tre[id].m+1, r));
}
}
线段树(区间更新)
int a[maxn];
struct TREE{
ll l, r, val, lazy;
void fun(ll tmp) {
lazy += tmp;
val += (r - l + 1) * tmp;
}
} tre[maxn*4];
void PushDown(int id) {
if (tre[id].lazy) {
tre[id<<1].fun(tre[id].lazy);
tre[id<<1|1].fun(tre[id].lazy);
tre[id].lazy = 0;
}
}
void PushUp(int id) {
tre[id].val = tre[id<<1].val + tre[id<<1|1].val;
}
void build(int id, int l, int r) {
tre[id].l = l, tre[id].r = r, tre[id].lazy = 0;
if (l == r) tre[id].val = a[l];
else {
int mid = (l+r) >> 1;
build(id<<1, l, mid);
build(id<<1|1, mid+1, r);
PushUp(id);
}
}
void update(int id, int st, int ed, int val) {
int l = tre[id].l, r = tre[id].r;
if (st <= l && ed >= r) tre[id].fun(val);
else {
PushDown(id);
int mid = (l+r) >> 1;
if (st <= mid) update(id<<1, st, ed, val);
if (ed > mid) update(id<<1|1, st, ed, val);
PushUp(id);
}
}
ll query(int id, int st, int ed) {
int l = tre[id].l, r = tre[id].r;
if (st <= l && ed >= r) return tre[id].val;
else {
PushDown(id);
int mid = (l+r) >> 1;
ll sum1 = 0, sum2 = 0;
if (st <= mid) sum1 = query(id<<1, st, ed);
if (ed > mid) sum2 = query(id<<1|1, st, ed);
PushUp(id);
return sum1 + sum2;
}
}
强连通分量+缩点
int n, m, low[maxn], pre[maxn], scc[maxn], scc_cnt, dfs_tim;
int in[maxn], out[maxn];
vector<int> G[maxn];
stack<int> S;
void init() {
dfs_tim = scc_cnt = 0;
memset(pre, 0, sizeof(pre));
memset(scc, 0, sizeof(scc));
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
for (int i = 1; i <= n; i++)
G[i].clear();
}
void dfs(int x) {
low[x] = pre[x] = ++dfs_tim;
S.push(x);
for (int i = 0; i < G[x].size(); i++) {
int u = G[x][i];
if (!pre[u]) {
dfs(u);
low[x] = min(low[x], low[u]);
}
else if (!scc[u])
low[x] = min(low[x], pre[u]);
}
if (low[x] == pre[x]) {
scc_cnt++;
while (1) {
int u = S.top(); S.pop();
scc[u] = scc_cnt;
if (u == x) break;
}
}
}
void solve() {
for (int i = 1; i <= n; i++) {
if (!pre[i]) dfs(i);
}
if (scc_cnt == 1) cout << 0 << endl;
else {
for (int i = 1; i <= n; i++) {
for (int j = 0; j < G[i].size(); j++) {
int u = G[i][j];
if (scc[u] != scc[i]) {
in[scc[u]] = out[scc[i]] = 1;
}
}
}
int QAQ = 0, HH = 0;
for (int i = 1; i <= scc_cnt; i++) {
if (!in[i]) QAQ++;
if (!out[i]) HH++;
}
cout << max(QAQ, HH) << endl;
}
}
int main() {
//cin.sync_with_stdio(false);
//freopen("isharp.in", "r", stdin);
//freopen("isharp.out", "w", stdout);
int t; cin >> t;
while (t--) {
cin >> n >> m;
init();
for (int i = 1; i <= m; i++) {
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v);
}
solve();
}
return 0;
}
KMP(SCU 4438)
char pri[maxn];
char w[maxn], p[maxn];
int Next[maxn], now[maxn];
void getnext(char *s, int len) {
int t1 = 0, t2;
Next[0] = t2 = -1;
while(t1 < len){
if(t2 == -1 || s[t1] == s[t2])
Next[++t1] = ++t2;
else t2 = Next[t2];
}
}
void kmp(char *s1, char *s2, int len1, int len2) {
int k = 0, t = 0;
for (int i = 0; i < len1; i++) {
pri[k] = s1[i];
while (t != -1 && s1[i] != s2[t]) t = Next[t];
t++;
now[k++] = t;
if (t == len2) {
k -= len2;
t = now[k-1];
}
}
pri[k] = 0;
}
背包
<1> 01背包(w[i]代表重量,v[i]代表价值,V代表背包容量)
for(int i=0;i<N;i++)
for(int j=V;j>=w[i];j--)
dp[j]=max(dp[j-w[i]]+v[i],dp[j]);
<2> 完全背包(完全背包跟01背包的代码很像)
for(int i=0;i<N;i++)
for(int j=w[i];j<=V;j++)
dp[j]=max(dp[j-w[i]]+v[i],dp[j]);
<3> 多重背包
说起多重背包,可以用单调队列优化,也可以用二进制优化,目前只学了二进制优化方法,以后补上单调队列算法优化。
多重背包其实就是01背包与完全背包的结合题。(f[i].w代表重量,f[i].v代表价值,f[i].t代表数量,w代表背包容量)
在二进制优化那边我的代码写的有点繁琐,可以更简洁,就交给你们啦。 吐舌头
for(int i=0;i<=k;i++)
{
int sum=f[i].w*f[i].t;
if(sum>=w) //完全背包
{
for(int j=f[i].w;j<=w;j++)
dp[j]=max(dp[j],dp[j-f[i].w]+f[i].v);
}
else //二进制优化转化成01背包求解
{
int aa=1,cc=1,m,g;
while(cc<f[i].t)
{
m=aa*f[i].w;
g=aa*f[i].v;
aa*=2;
cc+=aa;
for(int j=w;j>=m;j--)
dp[j]=max(dp[j],dp[j-m]+g);
}
m=(f[i].t-(cc-aa))*f[i].w;
g=(f[i].t-(cc-aa))*f[i].v;
for(int j=w;j>=m;j--)
dp[j]=max(dp[j],dp[j-m]+g);
}
}
矩阵快速幂
struct Ma{
ll n, m;
ll a[30][30];
void clear() {
n = m = 0;
memset(a, 0, sizeof(a));
}
Ma operator * (const Ma &b) const {
Ma tmp;
tmp.clear();
tmp.n = n; tmp.m = b.m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < b.m; j++) {
for (int k = 0; k < m; k++) {
tmp.a[i][j] |= (a[i][k] * b.a[k][j]);
//tmp.a[i][j] %= mod;
}
}
}
return tmp;
}
};
ll _pow(ll t) {
Ma M, F, E;
M.clear(), F.clear(),E.clear(); // 清空
M.n = M.m = F.n = F.m = E.n = E.m = 3; //大小
F.a[0][0] = 1, F.a[0][1] = 0, F.a[0][2] = 1; //F是初始矩阵、M是构造出的矩阵
for (int i = 0; i < 3; i++) {
E.a[i][i] = 1;
}
M.a[0][0] = 1, M.a[0][1] = 1, M.a[1][0] = 2;
M.a[2][0] = 1, M.a[2][2] = 1;
// 主要的
while (t) {
if (t & 1) E = M*E;
M = M*M;
t >>= 1;
}
F = F * E;
return F.a[0][0] % mod;
}
状态压缩的背包:
void get_sta() {
for (int i = 0; i < (1<<n); i++) {
if (ok(i))
sta[++len] = i, xx[i] = 1;
}
}
int solve_bag() {
for (int i = 1; i <= len; i++) {
for (int j = (1<<n) - 1; j >= 0; j--) {
if (!(sta[i] & j)) {
dp[sta[i]|j] = min(dp[sta[i]|j], dp[j] + 1);
}
}
}
return dp[(1<<n)-1] == INF ? -1 : dp[(1<<n)-1];
}
MTSP
for (int i = 0; i < (1<<n); i++) {
if (xx[i]) {
for (int j = 0; j < n; j++) {
if (i&(1<<j)) {
best[i] = min(best[i], en[j][i] + dis[j][0]);
for (int k = 0; k < n; k++) {
if (!(i&(1<<k))) {
en[k][i|(1<<k)] = min(en[k][i|(1<<k)], en[j][i] + dis[j][k]);
}
}
}
}
}
}
for (int i = 1; i < (1<<n); i++)
if (i&1)
for (int j = i&(i-1); j; j = i&(j-1))
best[i] = min(best[i], best[(i-j)|1] + best[j|1]);
return best[(1<<n)-1];

浙公网安备 33010602011771号