您的位置:首页 > 其它

[Template]省选复习计划

2017-04-17 22:44 218 查看

[Template]省选复习计划

字符串相关

KMP算法(luogu3375)

7′40′′

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1000005, MAXM = 1005;
char s1[MAXN], s2[MAXM];

int pi[MAXM];

void kmp_init(int len)
{
pi[0] = pi[1] = 0;
int j = 0;
for (int i = 2; i <= len; i++) {
while (j && s2[j+1] != s2[i]) j = pi[j];
if (s2[j+1] == s2[i]) j++;
pi[i] = j;
}
}

void kmp_match(int len)
{
int j = 0, p = strlen(s2+1);
for (int i = 1; i <= len; i++) {
while (j && s1[i] != s2[j+1]) j = pi[j];
if (s1[i] == s2[j+1]) ++j;
if (j == p) printf("%d\n", i-p+1), j = pi[j];
}
}

int main()
{
scanf("%s", s1+1), scanf("%s", s2+1);
kmp_init(strlen(s2+1));
kmp_match(strlen(s1+1));
for (int i = 1, l = strlen(s2+1); i <= l; i++)
printf("%d ", pi[i]);
return 0;
}


AC自动机(hdu2222)

32′42′′

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1000005;
int chl[MAXN][26], fail[MAXN], fin[MAXN], top = 0, root = 0, mak[MAXN];
void push(int &nd, char *str)
{
if (!nd) nd = ++top;
if (*str == '\0') fin[nd]++;
else push(chl[nd][*str-'a'], str+1);
}

struct node {
int to, next;
} edge[MAXN];
int head[MAXN], tp = 0;
void push(int i, int j)
{ ++tp, edge[tp] = (node) {j, head[i]}, head[i] = tp; }

queue<int> que;
void init()
{
fail[root] = 0, que.push(root);
while (!que.empty()) {
int tp = que.front(); que.pop();
for (int i = 0; i < 26; i++) {
if (!chl[tp][i]) continue;
int p = fail[tp];
while (p && !chl[p][i]) p = fail[p];
if (p) fail[chl[tp][i]] = chl[p][i];
else fail[chl[tp][i]] = root;
push(fail[chl[tp][i]], chl[tp][i]);
que.push(chl[tp][i]);
}
}
}

void match(int nd, char *str)
{
if (fin[nd]) mak[nd] = 1;
if (*str == '\0') return;
while (nd && !chl[nd][*str-'a']) nd = fail[nd];
if (nd) match(chl[nd][*str-'a'], str+1);
else match(root, str+1);
}

int dp[MAXN], siz[MAXN]; // 两次collect
int dfs1(int nd)
{
if (!nd) return 0;
if (siz[nd] != -1) return siz[nd];
for (int i = 0; i < 26; i++)
mak[nd] |= dfs1(chl[nd][i]);
return siz[nd] = mak[nd];
}

int dfs2(int nd)
{
if (dp[nd] != -1) return dp[nd];
dp[nd] = siz[nd];
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
dp[nd] |= dfs2(to);
}
return dp[nd];
}

char str[MAXN];

int T, n;

void clear()
{
top = root = tp = 0, memset(chl, 0, sizeof chl), memset(fail, 0, sizeof fail);
memset(fin, 0, sizeof fin), memset(mak, 0, sizeof mak);
memset(siz, -1, sizeof siz), memset(dp, -1, sizeof dp);
memset(head, 0, sizeof head);
}

int main()
{
scanf("%d", &T);
while (T--) {
clear();
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%s", str);
push(root, str);
}
init();
scanf("%s", str);
match(root, str);
dfs1(root), dfs2(root);
int ans = 0;
for (int i = 1; i <= top; i++)
ans += dfs2(i)*fin[i];
printf("%d\n", ans);
}
return 0;
}


SA

24′′04′,然而参考了模板…

第二次14′15′′

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1e5+5, N = 1e5;
struct ele {
int k[2], id;
ele(){}
ele(int a, int b, int c) { k[0] = a, k[1] = b, id = c; }
} RE[MAXN], RT[MAXN];
int sa[MAXN], rk[MAXN], height[MAXN], sum[MAXN], n;
char str[MAXN];

void radix_sort()
{
for (int y = 1; y >= 0; y--) {
memset(sum, 0, sizeof sum);
for (int i = 1; i <= n; i++) sum[RE[i].k[y]]++;
for (int i = 1; i <= N; i++) sum[i] += sum[i-1];
for (int i = n; i >= 1; i--) RT[sum[RE[i].k[y]]--] = RE[i];
for (int i = 1; i <= n; i++) RE[i] = RT[i];
}
for (int i = 1; i <= n; i++) {
rk[RE[i].id] = rk[RE[i-1].id];
if (RE[i].k[0] != RE[i-1].k[0] || RE[i].k[1] != RE[i-1].k[1])
rk[RE[i].id]++;
}
}

void calc_sa()
{
for (int i = 1; i <= n; i++) RE[i] = ele(str[i]-'a'+1, 0, i);
radix_sort();
for (int k = 1; k < n; k <<= 1) {
for (int i = 1; i <= n; i++) RE[i] = ele(rk[i], i+k<=n?rk[i+k]:0, i);
radix_sort();
}
for (int i = 1; i <= n; i++) sa[rk[i]] = i;
}

void calc_height()
{
int h = 0;
for (int i = 1; i <= n; i++) {
if (rk[i] == 1) h = 0;
else {
int k = sa[rk[i]-1];
if (--h < 0) h = 0;
while (str[i+h] == str[k+h]) h++;
}
height[rk[i]] = h;
}
}

int main()
{
scanf("%s", str+1);
n = strlen(str+1);
calc_sa(), calc_height();
for (int i = 1; i <= n; i++) printf("%d ", sa[i]); puts("");
for (int i = 2; i <= n; i++) printf("%d ", height[i]);
return 0;
}


SAM

luogu2852

8′59′′

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 40005;
map<int, int> chl[MAXN];
int fa[MAXN], maxl[MAXN], right_siz[MAXN];
int top = 1, root = 1, last = 1;

void push(int x)
{
int p = last, np = ++top; maxl[np] = maxl[p]+1, right_siz[np] = 1;
while (p && !chl[p][x]) chl[p][x] = np, p = fa[p];
if (!p) fa[np] = root;
else {
int q = chl[p][x];
if (maxl[q] == maxl[p] + 1) fa[np] = q;
else {
int nq = ++top; maxl[nq] = maxl[p]+1, chl[nq] = chl[q];
fa[nq] = fa[q], fa[q] = fa[np] = nq;
while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p];
}
}
last = np;
}

struct node {
int to, next;
} edge[MAXN];
int head[MAXN], tp = 0;
void push(int i, int j)
{ ++tp, edge[tp] = (node){j, head[i]}, head[i] = tp; }

int n, k, ans = 0;

void dfs(int nd)
{
for (int i = head[nd]; i; i = edge[i].next) {
dfs(edge[i].to);
right_siz[nd] += right_siz[edge[i].to];
}
if (right_siz[nd] >= k) ans = max(ans, maxl[nd]);
}

int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
int u; scanf("%d", &u);
push(u);
}
for (int i = 2; i <= top; i++) push(fa[i], i);
dfs(root);
cout << ans << endl;
return 0;
}


bzoj3238: [Ahoi2013]差异

约30′。因为longlong WA了一次。

后缀自动机parent树=逆序后缀树,后缀长度=maxl[nd]

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 500005*2;
int chl[MAXN][26], fa[MAXN], maxl[MAXN];
long long right_siz[MAXN];
int top = 1, root = 1, last = 1;
void push(int x)
{
int p = last, np = ++top; maxl[np] = maxl[p]+1, right_siz[np] = 1;
while (p && !chl[p][x]) chl[p][x] = np, p = fa[p];
if (!p) fa[np] = root;
else {
int q = chl[p][x];
if (maxl[q] == maxl[p] + 1) fa[np] = q;
else {
int nq = ++top; maxl[nq] = maxl[p]+1;
memcpy(chl[nq], chl[q], sizeof chl[q]);
fa[nq] = fa[q], fa[q] = fa[np] = nq;
while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p];
}
}
last = np;
}

struct node {
int to, next;
} edge[MAXN];
int head[MAXN], tp = 0;
void push(int i, int j)
{ edge[++tp] = (node) {j, head[i]}, head[i] = tp; }

char str[MAXN];

long long dfs(int nd)
{
long long ans = 0, beg = right_siz[nd];
for (int i = head[nd]; i; i = edge[i].next)
ans += dfs(edge[i].to), right_siz[nd] += right_siz[edge[i].to];
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
ans += right_siz[to]*(right_siz[nd]-right_siz[to])*maxl[nd];
}
ans += beg*(right_siz[nd]-beg)*maxl[nd];
return ans;
}

void init()
{
scanf("%s", str+1);
int n = strlen(str+1);
for (int i = n; i >= 1; i--)
push(str[i]-'a');
for (int i = 2; i <= top; i++) push(fa[i], i);
long long ans = 0;
for (int i = 1; i <= n; i++) ans += (long long)(n-i)*(n-i+1ll)+(long long)(1ll+n-i)*(n-i)/2;
cout << ans-dfs(root) << endl;
}

int main()
{
init();
return 0;
}


树相关

树上倍增

NOIP2013 货车运输

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 10005, MAXM = 100005;

struct p {
int x, y, d;
friend bool operator < (const p &a, const p &b)
{ return a.d > b.d; }
} edge_arr[MAXN];

struct node {
int to, next, dis;
} edge[MAXN];
int head[MAXN], top = 0;
void push(int i, int j, int k)
{ edge[++top] = (node){j, head[i], k}, head[i] = top; }
int fa[MAXN];
int findf(int nd)
{ return fa[nd] ? fa[nd] = findf(fa[nd]) : nd; }
int n, m;
int depth[MAXN], jmp[MAXN][20], min_val[MAXN][20], vis[MAXN];

void dfs(int nd, int f)
{
jmp[nd][0] = f, depth[nd] = depth[f] + 1;
for (int j = head[nd]; j; j = edge[j].next) {
int to = edge[j].to, d = edge[j].dis;
if (to == f) continue;
min_val[to][0] = d;
dfs(to, nd);
}
}

void init()
{
for (int j = 1; j < 20; j++)
for (int i = 1; i <= n; i++) {
jmp[i][j] = jmp[jmp[i][j-1]][j-1];
min_val[i][j] = min(min_val[i][j-1], min_val[jmp[i][j-1]][j-1]);
}
}

int lca(int a, int b)
{
if (depth[a] < depth[b]) swap(a, b);
for (int i = 0, d = depth[a]-depth[b]; i < 20; i++)
if ((1<<i)&d)
a = jmp[a][i];
if (a == b) return a;
for (int i = 19; i >= 0; i--)
if (jmp[a][i] != jmp[b][i])
a = jmp[a][i], b = jmp[b][i];
return jmp[a][0];
}

int query(int a, int b)
{
int c = lca(a, b);
if (findf(a) != findf(b)) return -1;
int ans = INT_MAX;
for (int i = 0, d = depth[a]-depth[c]; i < 20; i++)
if ((1<<i)&d)
ans = min(ans, min_val[a][i]), a = jmp[a][i];
for (int i = 0, d = depth[b]-depth[c]; i < 20; i++)
if ((1<<i)&d)
ans = min(ans, min_val[b][i]), b = jmp[b][i];
return ans;
}

int main()
{
memset(min_val, 127/3, sizeof min_val);
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
scanf("%d%d%d", &edge_arr[i].x, &edge_arr[i].y, &edge_arr[i].d);
sort(edge_arr+1, edge_arr+m+1);
for (int i = 1; i <= m; i++) {
int u = edge_arr[i].x, v = edge_arr[i].y, d = edge_arr[i].d;
if (findf(u) != findf(v)) {
fa[findf(u)] = findf(v);
push(u, v, d), push(v, u, d);
}
}
depth[0] = 0;
for (int i = 1; i <= n; i++)
if (fa[i] == 0)
dfs(i, 0);
init();
int q; scanf("%d", &q);
for (int i = 1; i <= q; i++) {
int u, v; scanf("%d%d", &u, &v);
printf("%d\n", query(u, v));
}
return 0;
}


树链剖分

luogu模板题

约50′

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005;

int lc[MAXN], rc[MAXN], l[MAXN], r[MAXN], root = 0;
long long sum[MAXN], lazy[MAXN], P;
int tp = 0;

void build_tree(int &nd, int opl, int opr)
{
nd = ++tp, l[nd] = opl, r[nd] = opr;
sum[nd] = lazy[nd] = 0;
if (opl < opr)
build_tree(lc[nd], opl, (opl+opr)/2), build_tree(rc[nd], (opl+opr)/2+1, opr);
}
void pdw(int nd)
{
if (!lazy[nd]) return;
if (lc[nd]) lazy[lc[nd]] += lazy[nd];
if (rc[nd]) lazy[rc[nd]] += lazy[nd];
(sum[nd] += lazy[nd]*(r[nd]-l[nd]+1)) %= P;
lazy[nd] = 0;
}
void modify(int nd, int opl, int opr, long long dt)
{
if (opl == l[nd] && opr == r[nd]) (lazy[nd] += dt) %= P;
else {
int mid = (l[nd]+r[nd])/2;
(sum[nd] += (opr-opl+1)*dt) %= P;
if (opr <= mid) modify(lc[nd], opl, opr, dt);
else if (opl >= mid+1) modify(rc[nd], opl, opr, dt);
else modify(lc[nd], opl, mid, dt), modify(rc[nd], mid+1, opr, dt);
}
}
long long query(int nd, int opl, int opr)
{
if (nd) pdw(nd);
if (opl == l[nd] && opr == r[nd]) return sum[nd]%P;
else {
int mid = (l[nd]+r[nd])/2;
if (opr <= mid) return query(lc[nd], opl, opr);
else if (opl >= mid+1) return query(rc[nd], opl, opr);
else return (query(lc[nd], opl, mid)+query(rc[nd], mid+1, opr))%P;
}
}

struct node {
int to, next;
} edge[MAXN*2];
int head[MAXN], top = 0;
void push(int i, int j)
{ edge[++top] = (node) {j, head[i]}, head[i] = top; }
int n, m, rt;
int siz[MAXN], id[MAXN], out[MAXN], ind[MAXN], rk[MAXN], depth[MAXN];
int id_in_ds = 0;
int fa[MAXN][21];

void dfs(int nd, int f)
{
fa[nd][0] = f, siz[nd] = 1, depth[nd] = depth[f] + 1;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
if (to == f) continue;
dfs(to, nd), siz[nd] += siz[to];
}
}

void dfs2(int nd, int from)
{
id[nd] = ++id_in_ds, ind[nd] = from;
modify(root, id[nd], id[nd], rk[nd]);
int hev = 0;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
if (depth[to] < depth[nd]) continue;
if (siz[to] > siz[hev]) hev = to;
}
if (!hev) { out[nd] = id_in_ds; return; }
dfs2(hev, from);
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
if (depth[to] < depth[nd]) continue;
if (to != hev) dfs2(to, to);
}
out[nd] = id_in_ds;
}

void init()
{
for (int j = 1; j <= 20; j++)
for (int i = 1; i <= n; i++)
fa[i][j] = fa[fa[i][j-1]][j-1];
}

int lca(int a, int b)
{
if (depth[a] < depth[b]) swap(a, b);
for (int d = depth[a]-depth[b], i = 0; i <= 20; i++)
if (d&(1<<i))
a = fa[a][i];
if (a == b) return a;
for (int i = 20; i >= 0; i--)
if (fa[a][i] != fa[b][i])
a = fa[a][i], b = fa[b][i];
return fa[a][0];
}

void add_path(int a, long long dt) // a到根
{
while (a) {
modify(root, id[ind[a]], id[a], dt);
a = fa[ind[a]][0];
}
}

void add_son(int a, int dt)
{ modify(root, id[a], out[a], dt); }

long long query_path(int a) //
{
long long ans = 0;
while (a) {
(ans += query(root, id[ind[a]], id[a])) %= P;
a = fa[ind[a]][0];
}
return ans;
}

long long query_son(int a)
{ return query(root, id[a], out[a]); }

int main()
{
scanf("%d%d%d%lld", &n, &m, &rt, &P);
for (int i = 1; i <= n; i++) scanf("%d", &rk[i]);
build_tree(root, 1, n);
for (int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
push(u, v), push(v, u);
}
depth[rt] = 0, dfs(rt, 0);
dfs2(rt, rt);
init();
for (int i = 1; i <= m; i++) {
int tp, x, y;
long long z;
scanf("%d", &tp);
if (tp == 1) {
scanf("%d%d%lld", &x, &y, &z);
int c = lca(x, y);
add_path(x, z), add_path(y, z);
add_path(c, -2*z);
modify(root, id[c], id[c], z);
} else if (tp == 2) {
scanf("%d%d", &x, &y);
int c = lca(x, y);
printf("%lld\n", ((query_path(x)+query_path(y)-2*query_path(c)+query(root, id[c], id[c]))%P+P)%P);
} else if (tp == 3) {
scanf("%d%lld", &x, &z);
add_son(x, z);
} else if (tp == 4) {
scanf("%d", &x);
printf("%lld\n", query_son(x));
} else throw;
}
return 0;
}


dfs序

bzoj4034: [HAOI2015]树上操作

这个题其实树剖很好写,不过dfs序的思路太神辣所以必须发…http://www.cnblogs.com/liyinggang/p/5965981.html

pdw写错+10086…

虽然dfs序理论复杂度O(nlgn)但是由于写法太渣跑的还没有链剖快…

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005*8;
int n, m;

int lc[MAXN], rc[MAXN], l[MAXN], r[MAXN];
long long sum[MAXN], lazy[MAXN];
long long num[MAXN], num_tmp[MAXN];
int root = 0, top_ds = 0;
void build(int &nd, int opl, int opr)
{
nd = ++top_ds, sum[nd] = 0;
l[nd] = opl, r[nd] = opr;
if (opl < opr) {
build(lc[nd], opl, (opl+opr)/2);
build(rc[nd], (opl+opr)/2+1, opr);
num[nd] = num[lc[nd]] + num[rc[nd]];
} else num[nd] = num_tmp[opl];
}

void pdw(int nd)
{
if (!lazy[nd]) return;
sum[nd] += num[nd]*lazy[nd];
if (lc[nd]) lazy[lc[nd]] += lazy[nd];
if (rc[nd]) lazy[rc[nd]] += lazy[nd];
lazy[nd] = 0;
}

void modify(int nd, int opl, int opr, long long dat)
{
if (opl == l[nd] && opr == r[nd]) lazy[nd] += dat, pdw(nd);
else {
pdw(nd);
int mid = (l[nd]+r[nd])>>1;
if (opr <= mid) modify(lc[nd], opl, opr, dat);
else if (opl >= mid+1) modify(rc[nd], opl, opr, dat);
else modify(lc[nd], opl, mid, dat), modify(rc[nd], mid+1, opr, dat);
pdw(lc[nd]), pdw(rc[nd]);
sum[nd] = sum[lc[nd]] + sum[rc[nd]];
}
}

void display(int nd, int tab)
{
if (!nd) return;
for (int i = 1; i <= tab; i++) putchar(' ');
printf("[%d,%d] --> sum = %lld, lazy = %lld, num = %lld\n", l[nd], r[nd], sum[nd], lazy[nd], num[nd]);
display(lc[nd], tab+2);
display(rc[nd], tab+2);
}

long long query(int nd, int opl, int opr)
{
pdw(nd);
if (opl == l[nd] && opr == r[nd]) return sum[nd];
else {
int mid = (l[nd]+r[nd])>>1;
if (opr <= mid) return query(lc[nd], opl, opr);
else if (opl >= mid+1) return query(rc[nd], opl, opr);
else return query(lc[nd], opl, mid)+query(rc[nd], mid+1, opr);
}
}

struct node {
int to, next;
} edge[MAXN];
int head[MAXN], top = 0;
void push(int i, int j)
{ edge[++top] = (node) {j, head[i]}, head[i] = top; }
int in[MAXN], out[MAXN], ds_top = 0;
int rk[MAXN];
void dfs(int nd, int f)
{
in[nd] = ++ds_top; num_tmp[in[nd]] = 1;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
if (to == f) continue;
dfs(to, nd);
}
out[nd] = ++ds_top; num_tmp[out[nd]] = -1;
}

void modify_point(int nd, long long dt)
{
modify(root, in[nd], in[nd], dt);
modify(root, out[nd], out[nd], dt);
}

void modify_tree(int nd, long long dt)
{ modify(root, in[nd], out[nd], dt); }

long long query_path(int nd)
{ return query(root, in[1], in[nd]); }

int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &rk[i]);
for (int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
push(u, v), push(v, u);
}
dfs(1, 0);
build(root, 1, 2*n);
for (int i = 1; i <= n; i++) {
modify_point(i, rk[i]);
}
for (int i = 1; i <= m; i++) {
int tp, a;
long long b;
scanf("%d", &tp);
if (tp == 1) {
scanf("%d%lld", &a, &b);
modify_point(a, b);
} else if (tp == 2) {
scanf("%d%lld", &a, &b);
modify_tree(a, b);
} else {
scanf("%d", &a);
printf("%lld\n", query_path(a));
}
}
return 0;
}


lct

bzoj3832 Tree

http://hzwer.com/4422.html

约1.5h,脑残原因:zig的时候先修改了p的fa,才判断is_rt(p)…

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 500005;

int chl[MAXN][2], fa[MAXN], dat[MAXN], sum[MAXN], top = 0;
int rev[MAXN], stk[MAXN], stop = 0, n, m;

bool is_rt(int nd)
{ return chl[fa[nd]][0] != nd && chl[fa[nd]][1] != nd; }

void pdw(int nd)
{
if (!rev[nd]) return;
int &lc = chl[nd][0], &rc = chl[nd][1];
if (lc) rev[lc] ^= 1;
if (rc) rev[rc] ^= 1;
swap(lc, rc), rev[nd] = 0;
}

inline void update(int nd)
{
sum[nd] = dat[nd]^sum[chl[nd][0]]^sum[chl[nd][1]];
}

void zig(int nd)
{
int p = fa[nd], g = fa[p];
int tp = chl[p][0] != nd, tg = chl[g][0] != p;
int son = chl[nd][tp^1];
if (!is_rt(p)) chl[g][tg] = nd;
fa[son] = p, fa[p] = nd, fa[nd] = g;
chl[nd][tp^1] = p, chl[p][tp] = son;
update(p), update(nd);
}

void splay(int nd)
{
stk[stop = 1] = nd;
for (int i = nd; !is_rt(i); i = fa[i]) stk[++stop] = fa[i];
while (stop) pdw(stk[stop--]);
while (!is_rt(nd)) {
int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
if (is_rt(p)) { zig(nd); break; }
else if (tp == tg) zig(p), zig(nd);
else zig(nd), zig(nd);
}
}

void access(int x)
{
for (int y = 0; x; x = fa[y = x])
splay(x), chl[x][1] = y, update(x);
}

void make_rt(int x)
{
access(x), splay(x);
rev[x] ^= 1;
}

int find_fa(int x)
{
access(x), splay(x);
while (chl[x][0]) {
if (x == chl[x][0]) throw;
x = chl[x][0];
}
return x;
}

void link(int x, int y)
{
if (find_fa(x) == find_fa(y)) return;
make_rt(x), fa[x] = y;
access(x);
}

void cut(int x, int y)
{
if (find_fa(x) != find_fa(y)) return;
make_rt(x);
access(y), splay(y);
if (chl[y][0] == x) chl[y][0] = 0, fa[x] = 0;
}

int query(int x, int y)
{
make_rt(x), access(y), splay(y);
if (find_fa(y) != x) return -1;
return sum[y];
}

void change(int x, int dt)
{
make_rt(x), splay(x), dat[x] = dt, update(x);
}

int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &dat[i]), update(i);
for (int i = 1; i <= m; i++) {
int tp, x, y;
scanf("%d%d%d", &tp, &x, &y);
if (tp == 0)
printf("%d\n", query(x, y));
else if (tp == 1)
link(x, y);
else if (tp == 2)
cut(x, y);
else change(x, y);
}
return 0;
}


bzoj2843: 极地旅行社

Description

不久之前,Mirko建立了一个旅行社,名叫“极地之梦”。这家旅行社在北极附近购买了N座冰岛,并且提供观光服

务。当地最受欢迎的当然是帝企鹅了,这些小家伙经常成群结队的游走在各个冰岛之间。Mirko的旅行社遭受一次

重大打击,以至于观光游轮已经不划算了。旅行社将在冰岛之间建造大桥,并用观光巴士来运载游客。Mirko希望

开发一个电脑程序来管理这些大桥的建造过程,以免有不可预料的错误发生。这些冰岛从1到N标号。一开始时这些

岛屿没有大桥连接,并且所有岛上的帝企鹅数量都是知道的。每座岛上的企鹅数量虽然会有所改变,但是始终在[0

, 1000]之间。你的程序需要处理以下三种命令:

1.”bridge A B”——在A与B之间建立一座大桥(A与B是不同的岛屿)。由于经费限制,这项命令被接受,当且仅当

A与B不联通。若这项命令被接受,你的程序需要输出”yes”,之

后会建造这座大桥。否则,你的程序需要输出”no”。

2.”penguins A X”——根据可靠消息,岛屿A此时的帝企鹅数量变为X。这项命令只是用来提供信息的,你的程序不

需要回应。

3.”excursion A B”——一个旅行团希望从A出发到B。若A与B连通,你的程序需要输出这个旅行团一路上所能看到的

帝企鹅数量(包括起点A与终点B),若不联通,你的程序需要输出”impossible”。

Input

第一行一个正整数N,表示冰岛的数量。

第二行N个范围[0,1000]的整数,为每座岛屿初始的帝企鹅数量。

第三行一个正整数M,表示命令的数量。接下来M行即命令,为题目描述所示。

1<=N<=30000,1<=M<=100000

16′04′′

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 30005;
int chl[MAXN][2], fa[MAXN], rev[MAXN], stk[MAXN], sum[MAXN], dat[MAXN], top = 0;
inline bool is_rt(int nd)
{ return chl[fa[nd]][0] != nd && chl[fa[nd]][1] != nd; }
inline void update(int nd)
{ sum[nd] = sum[chl[nd][0]]+sum[chl[nd][1]]+dat[nd]; }

void pdw(int nd)
{
if (!rev[nd]) return;
int &lc = chl[nd][0], &rc = chl[nd][1];
if (lc) rev[lc] ^= 1;
if (rc) rev[rc] ^= 1;
swap(lc, rc), rev[nd] = 0;
}

void zig(int nd)
{
int p = fa[nd], g = fa[p];
int tp = chl[p][0] != nd, tg = chl[g][0] != p, son = chl[nd][tp^1];
if (son) fa[son] = p;
if (!is_rt(p)) chl[g][tg] = nd;
fa[p] = nd, fa[nd] = g;
chl[nd][tp^1] = p, chl[p][tp] = son;
update(p), update(nd);
}
void splay(int nd)
{
stk[top = 1] = nd;
for (int i = nd; !is_rt(i); i = fa[i]) stk[++top] = fa[i];
while (top) pdw(stk[top--]);
while (!is_rt(nd)) {
int p = fa[nd], g = fa[p];
int tp = chl[p][0] != nd, tg = chl[g][0] != p;
if (is_rt(p)) {zig(nd); break; }
else if (tp == tg) zig(p), zig(nd);
else zig(nd), zig(nd);
}
}
void access(int x)
{
for (int y = 0; x; x = fa[y = x])
splay(x), chl[x][1] = y, update(x);
}
void make_rt(int x)
{ access(x), splay(x), rev[x] ^= 1; }
int find(int x)
{
access(x), splay(x);
while (chl[x][0]) x = chl[x][0];
return x;
}
void link(int x, int y)
{
if (find(x) == find(y)) return;
make_rt(x), access(x), splay(x);
fa[x] = y;
}
void change(int x, int dt)
{ make_rt(x), splay(x), dat[x] = dt, update(x); }
int query(int x, int y)
{ return make_rt(x), access(y), splay(y), sum[y]; }

int n, m;
char str[20];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d",&dat[i]), update(i);
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%s %d %d", str, &x, &y);
if (str[0] == 'e') {
if (find(x) != find(y)) puts("impossible");
else printf("%d\n", query(x, y));
} else if (str[0] == 'p') {
change(x, y);
} else if (str[0] == 'b') {
if (find(x) == find(y)) puts("no");
else
puts("yes"), link(x, y);
}
}
return 0;
}


数据结构

splay

bzoj1269: [AHOI2006]文本编辑器editor

被pdw支配的恐惧…

几个小操作的先后顺序一定要小心小心再小心啊…这次由于先检查siz后pushdown导致1h+调试…

约2h

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1024*1024*4;
int chl[MAXN][2], fa[MAXN], dat[MAXN], siz[MAXN], rev[MAXN];
int top = 0, root = 0;
inline void update(int nd)
{ if(!nd) return; siz[nd] = siz[chl[nd][0]]+siz[chl[nd][1]]+1; }

int stk[MAXN], skp = 0;

void pdw(int nd)
{
if (!rev[nd]) return;
int &lc = chl[nd][0], &rc = chl[nd][1];
rev[lc] ^= (lc != 0), rev[rc] ^= (rc != 0);
swap(lc, rc), rev[nd] = 0;
}

void zig(int nd)
{
pdw(nd);
int p = fa[nd], g = fa[p];
int tp = chl[p][0] != nd, tg = chl[g][0] != p, son = chl[nd][tp^1];
if (g) chl[g][tg] = nd; else root = nd;
if (son) fa[son] = p;
chl[nd][tp^1] = p, chl[p][tp] = son;
fa[p] = nd, fa[nd] = g;
update(p), update(nd);
}

void splay(int nd, int tar = 0)
{
stk[skp = 1] = nd;
for (int i = nd; fa[i]; i = fa[i]) stk[++skp] = fa[i];
while (skp) pdw(stk[skp--]);
while (fa[nd] != tar) {
int p = fa[nd], g = fa[p];
int tp = chl[p][0] != nd, tg = chl[g][0] != p;
if (g == tar) {zig(nd); break; }
else if (tp == tg) zig(p), zig(nd);
else zig(nd), zig(nd);
}
}

void dfs(int nd, int key)
{
if (!nd) return;
// pdw(nd);
// for (int i = 1; i <= tab; i++) putchar(' ');
printf("nd = %d, lc = %d, rc = %d, dat = %c, fa = %d-- siz = %d, rev = %d\n", nd, chl[nd][0], chl[nd][1], dat[nd], fa[nd], siz[nd], rev[nd]);
dfs(chl[nd][0], key);
// putchar(dat[nd]); if (key == nd) putchar('|');
dfs(chl[nd][1], key);
}
int kth(int k)
{
int nd = root;
while (pdw(nd), siz[chl[nd][0]] != k) {
nd = siz[chl[nd][0]] > k ? chl[nd][0] : (k -= siz[chl[nd][0]]+1, chl[nd][1]);
}
return nd;
}

int rk(int nd)
{
splay(nd);
return siz[chl[nd][0]];
}

int go_prev(int nd)
{ return kth(rk(nd)-1); }
int go_next(int nd)
{ return kth(rk(nd)+1); }
void print(int nd)
{ putchar(dat[go_next(nd)]); puts(""); }

int insert(int nd, int x)
{
int nx = go_next(nd);
splay(nd);
splay(nx, root);
pdw(root), pdw(nx);
chl[nx][0] = ++top, fa[top] = nx, dat[top] = x, update(top), update(nx), update(nd);
return top;
}
void del(int nd, int len)
{
int l = nd, r = kth(rk(nd)+len+1);
splay(l), splay(r, root);
pdw(l), pdw(r);
chl[r][0] = 0, update(r), update(l);
}
int reverse(int nd, int len)
{
int l = nd, r = kth(rk(nd)+len+1), k = rk(nd);
splay(l), splay(r, root);
pdw(l), pdw(r);
rev[chl[r][0]] ^= 1;
return kth(k);
}
int n, k;
char str[20], s[MAXN];

void get_str(char str[])
{
int k = -1, c;
do c = getchar(); while(c < 32 || c > 126);
while (c >= 32 && c <= 126) {
str[++k] = c;
c = getchar();
}
str[++k] = '\0';
}
int main()
{
root = ++top, dat[top] = 0, chl[root][1] = ++top, dat[top] = 1;
fa[top] = top-1;
update(top), update(top-1);
scanf("%d", &n);
int nd = top-1;
for (int i = 1; i <= n; i++) {
scanf("%s", str);
switch(str[0]) {
case 'M': scanf("%d", &k); nd = kth(k); break;
case 'I':
scanf("%d", &k);
get_str(s);
for (int i = 0, x = nd; i < k; i++)
x = insert(x, s[i]);
break;
case 'D': scanf("%d", &k), del(nd, k); break;
case 'R': scanf("%d", &k), nd = reverse(nd, k); break;
case 'G': print(nd); break;
case 'P': nd = go_prev(nd); break;
case 'N': nd = go_next(nd); break;
}
}
return 0;
}


线段树

主席树

无修改区间k大。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005, lgn = 21;

int lc[MAXN*lgn], rc[MAXN*lgn], l[MAXN*lgn], r[MAXN*lgn], sum[MAXN*lgn];
int root[MAXN], top = 0;
int n, m;

void build(int &nd, int opl, int opr)
{
nd = ++top;
l[nd] = opl, r[nd] = opr, sum[nd] = 0;
if (opl < opr)
build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);
}

void push(int prev, int &nd, int pos)
{
nd = ++top;
l[nd] = l[prev], r[nd] = r[prev];
if (l[prev] == r[prev]) sum[nd] = sum[prev]+1;
else {
int mid = (l[prev]+r[prev])/2;
if (pos <= mid) push(lc[prev], lc[nd], pos), rc[nd] = rc[prev];
else push(rc[prev], rc[nd], pos), lc[nd] = lc[prev];
sum[nd] = sum[lc[nd]]+sum[rc[nd]];
}
}

void dfs(int nd, int tab = 0)
{
if (!nd) return;
for (int i = 1; i <= tab; i++) putchar(' ');
printf("[%d,%d] -- sum = %d\n", l[nd], r[nd], sum[nd]);
dfs(lc[nd], tab+2), dfs(rc[nd], tab+2);
}

int query(int opl, int opr, int k)
{
int i = 1, j = n, mid;
int a = root[opl-1], b = root[opr];
k--;
while (i < j) {
mid = (i+j)>>1;
if (sum[lc[b]]-sum[lc[a]] <= k) k -= sum[lc[b]]-sum[lc[a]], i = mid+1, a = rc[a], b = rc[b];
else j = mid, a = lc[a], b = lc[b];
}
return i;
}

int d[MAXN];
int dx[MAXN];

void dx_init()
{
memcpy(dx, d, sizeof d);
sort(dx+1, dx+n+1);
}

int dx_num(int nd)
{ return lower_bound(dx+1, dx+n+1, nd)-dx; }

int main()
{
scanf("%d%d", &n, &m);
build(root[0], 1, n);
for (int i = 1; i <= n; i++)
scanf("%d", &d[i]);
dx_init();
for (int i = 1; i <= n; i++) {
push(root[i-1], root[i], dx_num(d[i]));
}
for (int i = 1; i <= m; i++) {
int u, v, k;
scanf("%d%d%d", &u, &v, &k);
cout << dx[query(u, v, k)] << endl;
}
return 0;
}


其他

FFT

大爷题解:http://www.cnblogs.com/iiyiyi/p/5717520.html

好像把一道好题变成练模板了..之后补分析吧..

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 300005;
int rev[MAXN], n;
typedef complex<double> Complex;
Complex A[MAXN];
const double PI = acos(-1);
void fft(Complex a[], int n, int flag)
{
int lgn = int(log2(n)+0.01);
rev[0] = 0;
for (int i = 1; i < n; i++) rev[i] = (rev[i>>1]>>1)|((1<<(lgn-1))*(i&1));
for (int i = 0; i < n; i++) A[i] = a[rev[i]];
for (int k = 2; k <= n; k <<= 1) {
Complex dw = Complex(cos(2*PI/k), flag*sin(2*PI/k));
for (int i = 0; i < n; i += k) {
Complex w = Complex(1, 0), u, v;
for (int j = 0; j < (k>>1); j++) {
u = A[i+j], v = w*A[i+j+(k>>1)];
A[i+j] = u+v, A[i+j+(k>>1)] = u-v;
w *= dw;
}
}
}
for (int i = 0; i < n; i++)
a[i] = A[i]/(flag==1?Complex(1,0):Complex(n,0));
}

long long k[MAXN];
int dat[MAXN];

Complex a[MAXN], b[MAXN], c[MAXN];

int main()
{
scanf("%d", &n);
int N = 1, mx = 0;
for (int i = 0; i < n; i++) {
int t; scanf("%d", &t); dat[i] = t;
mx = max(mx, t);
a[t] += Complex(1, 0);
b[2*t] += Complex(1, 0);
c[3*t] += Complex(1, 0);
}
while (N <= mx*3) N<<=1;
fft(a, N, 1), fft(b, N, 1), fft(c, N, 1);
for (int i = 0; i < N; i++)
a[i]=(a[i]*a[i]*a[i]-Complex(3, 0)*a[i]*b[i]+Complex(2, 0)*c[i])/Complex(6, 0)+(a[i]*a[i]-b[i])/Complex(2, 0)+a[i];
fft(a, N, -1);
for (int i = 0; i < N; i++) {
k[i] += (long long)(a[i].real()+0.1);
}
for (int i = 0; i < N; i++)
if (k[i])
printf("%d %lld\n", i, k[i]);
return 0;
}


Tarjan

bzoj2140 稳定婚姻

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 10005, MAXM = 100005;
struct node {
int to, next;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j)
{ edge[++top] = (node){j, head[i]}, head[i] = top; }

int dfn[MAXN], low[MAXN], stk[MAXN], instk[MAXN], stop = 0, dfs_top = 0;
int gp[MAXN], gp_top = 0;
int n, m, strtop = 0;
map<string, int> tab;
string str[MAXN];
string s1, s2;

void tarjan(int nd)
{
stk[++stop] = nd, instk[nd] = 1, dfn[nd] = low[nd] = ++dfs_top;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]);
else if (instk[to]) low[nd] = min(low[nd], dfn[to]);
}
if (dfn[nd] == low[nd]) {
int now = 0; gp_top++;
// printf(" -- Group %d --\n", gp_top);
do {
now = stk[stop--];
gp[now] = gp_top;
instk[now] = 0;
// cerr << str[now] << " ";
} while (now != nd);
// puts("");
}
}

int cpx[MAXN], cpy[MAXN];

int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
cin >> s1 >> s2;
if (!tab.count(s1)) tab[s1] = ++strtop, str[strtop] = s1;
if (!tab.count(s2)) tab[s2] = ++strtop, str[strtop] = s2;
push(tab[s2], tab[s1]);
cpx[i] = tab[s1], cpy[i] = tab[s2];
}
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
cin >> s1 >> s2;
push(tab[s1], tab[s2]);
}
for (int i = 1; i <= strtop; i++)
if (!dfn[i])
tarjan(i);
for (int i = 1; i <= n; i++)
if (gp[cpx[i]] == gp[cpy[i]])
puts("Unsafe");
else
puts("Safe");
return 0;
}


dinic

CQOI2015 网络吞吐量

spfa居然写跪了…没救了这

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 2005, MAXM = 200005;
struct node {
int to, next;
long long flow;
int neg;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j, long long f)
{
++top, edge[top] = (node){j, head[i], f, top+1}, head[i] = top;
++top, edge[top] = (node){i, head[j], 0, top-1}, head[j] = top;
}

const long long inf = 23333333333333ll;
int S, T, n, m;

int lev[MAXN], vis[MAXN], bfstime = 0;
queue<int> que;

bool bfs()
{
que.push(S), lev[S] = 0, vis[S] = ++bfstime;
while (!que.empty()) {
int t = que.front(); que.pop();
for (int i = head[t]; i; i = edge[i].next) {
int to = edge[i].to;
long long d = edge[i].flow;
if (!d || vis[to] == bfstime) continue;
vis[to] = bfstime, que.push(to), lev[to] = lev[t]+1;
}
}
return vis[T] == bfstime;
}

long long dfs(int nd, long long flow = inf)
{
if (!flow || nd == T) return flow;
long long t, ans = 0;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
long long d = edge[i].flow;
if (!d || lev[to] != lev[nd]+1) continue;
t = dfs(to, min(flow, d));
ans += t, flow -= t;
edge[i].flow -= t, edge[edge[i].neg].flow += t;
}
if (flow) lev[nd] = -1;
return ans;
}

long long dinic()
{
long long ans = 0;
while (bfs()) ans += dfs(S);
return ans;
}

long long dis[MAXN];
int inq[MAXN];
long long rk[MAXN];

node g2[MAXM];
int h2[MAXN], tp = 0;
void push2(int i, int j, long long k)
{ ++tp, g2[tp] = (node){j, h2[i], k, 0}, h2[i] = tp; }

void spfa()
{
memset(dis, 127/3, sizeof dis);
memset(inq, 0, sizeof inq);
dis[S] = 0, que.push(S), inq[S] = 1;
while (!que.empty()) {
int t = que.front(); que.pop(), inq[t] = 0;
for (int i = h2[t]; i; i = g2[i].next) {
int to = g2[i].to, d = g2[i].flow;
if (dis[to] > dis[t] + d) {
dis[to] = dis[t] + d;
if (!inq[to])
inq[to] = 1, que.push(to);
}
}
}
}

int main()
{
scanf("%d%d", &n, &m), S = 1, T = n+n;
for (int i = 1; i <= m; i++) {
int u, v;
long long d; scanf("%d%d%lld", &u, &v, &d);
push2(u, v, d), push2(v, u, d);
}
for (int i = 1; i <= n; i++) scanf("%lld", &rk[i]);
spfa();
for (int i = 1; i <= n; i++)
for (int j = h2[i]; j; j = g2[j].next) {
int to = g2[j].to;
long long d = g2[j].flow;
if (dis[to] == dis[i] + d) {
push(i+n, to, inf);
// cout << i << "--" << d << "->" << to << endl;
}
}
push(1, n+1, inf), push(n, n+n, inf);
for (int i = 2; i < n; i++) push(i, i+n, rk[i]);
cout << dinic() << endl;
return 0;
}


spfa费用流

[Noi2008]志愿者招募

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 2005, MAXM = 100005;
struct node {
int to, next;
long long flow, cost;
int neg;
} edge[MAXM];
int head[MAXN], top = 0, S = 2000, T = 2001;
long long inf = 23333333333333ll;
void push(int i, int j, long long f, long long c)
{
++top, edge[top] = (node){j, head[i], f, c, top+1}, head[i] = top;
++top, edge[top] = (node){i, head[j], 0, -c, top-1}, head[j] = top;
}
void push_lim(int i, int j, long long mf)
{
push(S, j, mf, 0), push(i, T, mf, 0);
push(i, j, inf, 0);
}
long long dis[MAXN];
int vis[MAXN], pre[MAXN], pre_edge[MAXN], n, m;
queue<int> que;
bool spfa(long long &cost)
{
memset(dis, 127/3, sizeof dis);
memset(vis, 0, sizeof vis);
memset(pre, 0, sizeof pre);
memset(pre_edge, 0, sizeof pre_edge);
vis[S] = 1, dis[S] = 0, que.push(S);
while (!que.empty()) {
int t = que.front(); que.pop(); vis[t] = 0;
for (int i = head[t]; i; i = edge[i].next) {
int to = edge[i].to, c = edge[i].cost;
if (!edge[i].flow) continue;
if (dis[to] > dis[t] + c) {
dis[to] = dis[t] + c;
pre[to] = t, pre_edge[to] = i;
if (!vis[to])
vis[to] = 1, que.push(to);
}
}
}
if (dis[T] >= inf) return 0;
long long mf = inf;
for (int i = T; i != S; i = pre[i]) mf = min(mf, edge[pre_edge[i]].flow);
for (int i = T; i != S; i = pre[i]) edge[pre_edge[i]].flow -= mf, edge[edge[pre_edge[i]].neg].flow += mf;
cost += dis[T]*mf;
return 1;
}

long long mcf()
{
long long ans = 0;
while (spfa(ans));
return ans;
}

int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
long long u; scanf("%lld", &u);
push_lim(i, i+1, u);
}
for (int i = 1; i <= m; i++) {
int l, r; long long cost;
scanf("%d%d%lld", &l, &r, &cost);
push(r+1, l, inf, cost);
}
cout << mcf() << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: