[关闭]
@ljt12138 2017-04-13T23:43:36.000000Z 字数 18066 阅读 818

bzoj刷题记录4.10-4.14


bzoj1093: [ZJOI2007]最大半联通子图

仍然缩点。缩完点之后每个半联通子图就相当于一条带权链(权值是一个scc的点数)。之后dp即可。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005, MAXM = 2000005;
  4. struct g {
  5. struct node {
  6. int to, next;
  7. } edge[MAXM];
  8. int head[MAXN], top;
  9. g(){ top = 0, memset(head, 0, sizeof head); }
  10. void push(int i, int j)
  11. { edge[++top] = (node) {j, head[i]}, head[i] = top; }
  12. }g, g1;
  13. int dfn[MAXN], low[MAXN], stk[MAXN], top = 0, dft = 0;
  14. int gp[MAXN], gtop = 0, gsiz[MAXN], vis[MAXN], n, m;
  15. void tarjan(int nd)
  16. {
  17. dfn[nd] = low[nd] = ++dft;
  18. stk[++top] = nd, vis[nd] = 1;
  19. for (int i = g.head[nd]; i; i = g.edge[i].next) {
  20. int to = g.edge[i].to;
  21. if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]);
  22. else if (vis[to]) low[nd] = min(low[nd], dfn[to]);
  23. }
  24. if (dfn[nd] == low[nd]) {
  25. int now; ++gtop;
  26. do {
  27. now = stk[top--], vis[now] = 0, gp[now] = gtop, gsiz[gtop]++;
  28. } while (now != nd);
  29. }
  30. }
  31. long long x;
  32. set<pair<int,int> > hst;
  33. int dp[MAXN], cnt[MAXN];
  34. int dfs(int nd)
  35. {
  36. if (dp[nd] != -1) return dp[nd];
  37. dp[nd] = gsiz[nd];
  38. for (int i = g1.head[nd]; i; i = g1.edge[i].next)
  39. dp[nd] = max(dp[nd], dfs(g1.edge[i].to)+gsiz[nd]);
  40. return dp[nd];
  41. }
  42. int dfs_cnt(int nd)
  43. {
  44. if (cnt[nd] != -1) return cnt[nd];
  45. if (!g1.head[nd]) return 1%x;
  46. cnt[nd] = 0;
  47. for (int i = g1.head[nd]; i; i = g1.edge[i].next) {
  48. int to = g1.edge[i].to;
  49. if (dp[nd] == dp[to] + gsiz[nd]) (cnt[nd] += dfs_cnt(to)) %= x;
  50. }
  51. return cnt[nd];
  52. }
  53. void work()
  54. {
  55. for (int i = 1; i <= n; i++)
  56. if (!dfn[i])
  57. tarjan(i);
  58. for (int i = 1; i <= n; i++)
  59. for (int j = g.head[i]; j; j = g.edge[j].next) {
  60. int to = g.edge[j].to;
  61. if (gp[i] != gp[to] && !hst.count(make_pair(gp[i], gp[to]))) {
  62. hst.insert(make_pair(gp[i], gp[to]));
  63. g1.push(gp[to], gp[i]); // G^R
  64. }
  65. }
  66. memset(dp, -1, sizeof dp), memset(cnt, -1, sizeof cnt);
  67. int ans1; long long ans2; ans1 = ans2 = 0;
  68. for (int i = 1; i <= gtop; i++)
  69. ans1 = max(ans1, dfs(i));
  70. for (int i = 1; i <= gtop; i++)
  71. if (dfs(i) == ans1)
  72. (ans2 += dfs_cnt(i)) %= x;
  73. printf("%d\n%lld\n", ans1, ans2);
  74. }
  75. int main()
  76. {
  77. scanf("%d%d%lld", &n, &m, &x);
  78. for (int i = 1; i <= m; i++) {
  79. int u, v; scanf("%d%d", &u, &v), g.push(u, v);
  80. }
  81. work();
  82. return 0;
  83. }

bzoj2208: [JSOI2010] 联通数

缩点后暴力可过..
但是貌似有更好的算法??比如在拓扑图上随意dfs一棵生成树然后dfs序维护??
尚不清楚复杂度是否更优。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 2005, MAXM = MAXN*MAXN;
  4. struct graph {
  5. struct node {
  6. int to, next;
  7. } edge[MAXM];
  8. int head[MAXN], top;
  9. graph(){top = 0, memset(head, 0, sizeof head); }
  10. void push(int i, int j)
  11. { ++top, edge[top] = (node) {j, head[i]}, head[i] = top; }
  12. } g, g1;
  13. int dfn[MAXN], dft = 0, low[MAXN], vis[MAXN];
  14. int stk[MAXN], top = 0;
  15. int gp[MAXN], gtop = 0, gsiz[MAXN], n;
  16. void tarjan(int nd)
  17. {
  18. vis[nd] = 1, dfn[nd] = low[nd] = ++dft, stk[++top] = nd;
  19. for (int i = g.head[nd]; i; i = g.edge[i].next) {
  20. int to = g.edge[i].to;
  21. if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]);
  22. else if (vis[to]) low[nd] = min(low[nd], dfn[to]);
  23. }
  24. if (dfn[nd] == low[nd]) {
  25. int now; ++gtop; //printf(" -- Group %d --\n", gtop);
  26. do {
  27. now = stk[top--];
  28. gp[now] = gtop, gsiz[gtop]++, vis[now] = 0;
  29. // cerr << now << " ";
  30. } while(now != nd); //puts("");
  31. }
  32. }
  33. int bfstime = 0;
  34. queue<int> que;
  35. int lkt[MAXN][MAXN];
  36. void work()
  37. {
  38. for (int i = 1; i <= n; i++)
  39. if (!dfn[i])
  40. tarjan(i);
  41. for (int i = 1; i <= n; i++)
  42. for (int j = g.head[i]; j; j = g.edge[j].next) {
  43. int to = g.edge[j].to;
  44. if (gp[to] != gp[i] && !lkt[gp[i]][gp[to]]) {
  45. lkt[gp[i]][gp[to]] = 1;
  46. g1.push(gp[i], gp[to]);
  47. }
  48. }
  49. int ans = 0;
  50. memset(vis, 0, sizeof vis);
  51. for (int i = 1; i <= gtop; i++) {
  52. ++bfstime;
  53. que.push(i), vis[i] = bfstime;
  54. int cnt = 0;
  55. while (!que.empty()) {
  56. int t = que.front(); que.pop(), cnt += gsiz[t];
  57. for (int i = g1.head[t]; i; i = g1.edge[i].next) {
  58. int to = g1.edge[i].to;
  59. if (vis[to] != bfstime)
  60. vis[to] = bfstime, que.push(to);
  61. }
  62. }
  63. ans += cnt*gsiz[i];
  64. }
  65. cout << ans << endl;
  66. }
  67. char str[2005];
  68. int main()
  69. {
  70. scanf("%d", &n);
  71. for (int i = 1; i <= n; i++) {
  72. scanf("%s", str+1);
  73. for (int j = 1; j <= n; j++)
  74. if (str[j] == '1')
  75. g.push(i, j);
  76. }
  77. work();
  78. return 0;
  79. }

4.11 更新

今天来一波字符串。

bzoj3172: [Tjoi2013]单词

这个题就比较神了。首先建出AC自动机,然后先求出每个节点的“顺着路过的总数dp[nd]”,也就是trie树上子树finish标记的总数;然后每个节点表示的串出现的次数就是某个节点fail树的子树中所有dp[nd]的总和。

第一次做反了...
形如

  1. sher
  2. shers
  3. her

的数据可以hack。因为shers不会算入her中去。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 3000005;
  4. int chl[MAXN][26], fail[MAXN], fin[MAXN], top = 0, root = 0;
  5. vector<int> ids[MAXN];
  6. int new_node()
  7. { return ++top, fail[top] = fin[top] = 0, memset(chl[top],0, sizeof chl[top]), top; }
  8. void push(int &nd, const char *str, int id)
  9. {
  10. if (nd == 0) nd = new_node();
  11. if (*str == '\0') fin[nd]++, ids[nd].push_back(id);
  12. else push(chl[nd][*str-'a'], str+1, id);
  13. }
  14. struct node {
  15. int to, next;
  16. } edge[MAXN];
  17. int head[MAXN], tp_edge = 0;
  18. void push(int i, int j)
  19. { ++tp_edge, edge[tp_edge] = (node) {j, head[i]}, head[i] = tp_edge; }
  20. int siz[MAXN], n;
  21. queue<int> que;
  22. void init()
  23. {
  24. que.push(root); fail[root] = 0;
  25. while (!que.empty()) {
  26. int t = que.front(); que.pop();
  27. for (int i = 0; i < 26; i++) if (chl[t][i]) {
  28. int p = fail[t];
  29. while (p && !chl[p][i]) p = fail[p];
  30. if (!p) fail[chl[t][i]] = root;
  31. else fail[chl[t][i]] = chl[p][i];
  32. que.push(chl[t][i]);
  33. push(fail[chl[t][i]], chl[t][i]);
  34. }
  35. }
  36. }
  37. long long res[MAXN];
  38. long long dp[MAXN];
  39. int dfs(int nd)
  40. {
  41. if (siz[nd] != -1) return siz[nd];
  42. siz[nd] = dp[nd];
  43. for (int i = head[nd]; i; i = edge[i].next) {
  44. int to = edge[i].to;
  45. siz[nd] += dfs(to);
  46. }
  47. return siz[nd];
  48. }
  49. long long dfs2(int nd)
  50. {
  51. if (dp[nd] != -1) return dp[nd];
  52. dp[nd] = fin[nd];
  53. for (int i = 0; i < 26; i++)
  54. if (chl[nd][i])
  55. dp[nd] += dfs2(chl[nd][i]);
  56. return dp[nd];
  57. }
  58. char str[MAXN];
  59. int main()
  60. {
  61. scanf("%d", &n);
  62. for (int i = 1; i <= n; i++) {
  63. scanf("%s", str);
  64. push(root, str, i);
  65. }
  66. init();
  67. memset(siz, -1, sizeof siz);
  68. memset(dp, -1, sizeof dp);
  69. dfs2(root);
  70. dfs(root);
  71. for (int i = 1; i <= top; i++)
  72. for (int j = 0; j < fin[i]; j++)
  73. res[ids[i][j]] = siz[i];
  74. for (int i = 1; i <= n; i++)
  75. printf("%lld\n", res[i]);
  76. return 0;
  77. }

bzoj1090: [SCOI2003]字符串折叠

首先|S|100告诉我们必然不是什么高端结构...

区间dp是正解,方程容易想到,唯一的字符串trick就是用hashk判断相等。

特别注意取某一区间hash的小技巧。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 105;
  4. char str[MAXN];
  5. int n;
  6. unsigned long long hash_tab[MAXN], pwr[MAXN];
  7. unsigned long long hash_val(int i, int j)
  8. { return hash_tab[j]-hash_tab[i-1]*pwr[j-i+1]; }
  9. int dp[MAXN][MAXN];
  10. int len(int num)
  11. { return num <= 9 ? 1 : (num <= 99 ? 2 : 3); }
  12. int dfs(int i, int j)
  13. {
  14. if (dp[i][j] != -1) return dp[i][j];
  15. if (i == j) return 1;
  16. dp[i][j] = INT_MAX;
  17. for (int k = i; k < j; k++)
  18. dp[i][j] = min(dp[i][j], dfs(i,k)+dfs(k+1,j));
  19. for (int k = 1; k <= j-i+1; k++) { // 枚举每一块长度
  20. if ((j-i+1)%k != 0) continue;
  21. int flag = 1; unsigned long long val = 0;
  22. for (int p = 0; p < (j-i+1)/k; p++) {
  23. if (p == 0) val = hash_val(i+p*k, i+(p+1)*k-1);
  24. else if (val != hash_val(i+p*k, i+(p+1)*k-1)) { flag = 0; break; }
  25. }
  26. if (flag) dp[i][j] = min(dp[i][j], dfs(i, i+k-1)+2+len((j-i+1)/k));
  27. }
  28. return dp[i][j];
  29. }
  30. int main()
  31. {
  32. scanf("%s", str+1), n = strlen(str+1);
  33. pwr[0] = 1;
  34. for (int i = 1; i <= n; i++) pwr[i] = pwr[i-1]*31;
  35. for (int i = 1; i <= n; i++) hash_tab[i] = hash_tab[i-1]*31+(str[i]-'A'+1);
  36. memset(dp, -1, sizeof dp);
  37. cout << dfs(1, n) << endl;
  38. return 0;
  39. }

bzoj2124: 等差子序列

乍一看和字符串毫无关系...
事实上,存在一个等差数列当且仅当存在三个点i<j<k,满足:

ai=aj+d,ak=ajd

然后对于这种对称的处理思路就两种:

  1. FFT
  2. 回文串

FFT貌似不太好处理,但回文串很兹瓷啊。用线段树记录每个点是否存在1/2并维护区间哈希,然后正反算哈希判断是不是相等即可。如果在某一时刻iai两侧不对称,就必然有一段回文串,也就有等差数列。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 10005;
  4. unsigned long long hash_tab[MAXN*4], hash_rev[MAXN*4], power[MAXN];
  5. int lc[MAXN*4], rc[MAXN*4], l[MAXN*4], r[MAXN*4], top = 0, root = 0;
  6. int n, a[MAXN];
  7. inline int siz(int nd) { return r[nd]-l[nd]+1; }
  8. void build(int &nd, int opl, int opr)
  9. {
  10. nd = ++top, hash_tab[nd] = hash_rev[nd] = 1, lc[nd] = rc[nd] = 0, l[nd] = opl, r[nd] = opr;
  11. if (opl < opr) {
  12. build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);
  13. hash_tab[nd] = hash_tab[lc[nd]]+power[siz(lc[nd])]*hash_tab[rc[nd]];
  14. hash_rev[nd] = hash_rev[rc[nd]]+power[siz(rc[nd])]*hash_rev[lc[nd]];
  15. }
  16. }
  17. void modify(int nd, int pos)
  18. {
  19. if (l[nd] == r[nd]) hash_tab[nd] = hash_rev[nd] = 2;
  20. else {
  21. modify(pos<=(l[nd]+r[nd])/2?lc[nd]:rc[nd], pos);
  22. hash_tab[nd] = hash_tab[lc[nd]]+power[siz(lc[nd])]*hash_tab[rc[nd]];
  23. hash_rev[nd] = hash_rev[rc[nd]]+power[siz(rc[nd])]*hash_rev[lc[nd]];
  24. }
  25. }
  26. unsigned long long query(int nd, int opl, int opr)
  27. {
  28. if (l[nd] == opl && r[nd] == opr) return hash_tab[nd];
  29. else {
  30. int mid = (l[nd]+r[nd])/2;
  31. if (opr <= mid) return query(lc[nd], opl, opr);
  32. else if (opl > mid) return query(rc[nd], opl, opr);
  33. else return query(lc[nd], opl, mid)+power[mid-opl+1]*query(rc[nd], mid+1, opr);
  34. }
  35. }
  36. unsigned long long query_reversed(int nd, int opl, int opr)
  37. {
  38. if (l[nd] == opl && r[nd] == opr) return hash_rev[nd];
  39. else {
  40. int mid = (l[nd]+r[nd])/2;
  41. if (opr <= mid) return query_reversed(lc[nd], opl, opr);
  42. else if (opl > mid) return query_reversed(rc[nd], opl, opr);
  43. else return power[opr-mid]*query_reversed(lc[nd], opl, mid)+query_reversed(rc[nd], mid+1, opr);
  44. }
  45. }
  46. void init()
  47. {
  48. scanf("%d", &n);
  49. top = root = 0;
  50. build(root, 1, n);
  51. for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
  52. }
  53. int main()
  54. {
  55. int T; scanf("%d", &T);
  56. power[0] = 1;
  57. for (int i = 1; i <= 10000; i++) power[i] = power[i-1]*31;
  58. while (T--) {
  59. init();
  60. int flag = 0;
  61. for (int i = 1; i <= n; i++) {
  62. // cerr << query(root, 1, 3) << "--" << query_reversed(root, 1, 3) << endl;
  63. if (a[i] <= n-a[i]+1) {
  64. if (i >= 2 && i < n && query(root, 1, 2*a[i]-1) != query_reversed(root, 1, 2*a[i]-1)) {
  65. flag = 1; break;
  66. }
  67. } else {
  68. int k = 2*(n-a[i]+1)-1;
  69. if (i >= 2 && i < n && query(root, n-k+1, n) != query_reversed(root, n-k+1, n)) {
  70. flag = 1; break;
  71. }
  72. }
  73. modify(root, a[i]);
  74. }
  75. if (flag) puts("Y");
  76. else puts("N");
  77. }
  78. return 0;
  79. }

bzoj3207: 花神的嘲讽计划Ⅰ

首先k20就可以暴力算出来每个块的哈希,然后就变成一个在区间内有没有某个值的问题了。莫队可解,O(nn)但跑比谁都快。

注意:hash一定要用ull...

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 400005, lgn = 20;
  4. int n, m, k, bas, sqr;
  5. unsigned long long hash_val(int a[], int l, int r)
  6. {
  7. unsigned long long ans = 0;
  8. for (int i = l; i <= r; i++)
  9. ans = ans*bas+a[i];
  10. return ans;
  11. }
  12. struct query {
  13. int l, r, dat, id, ans;
  14. friend bool operator < (const query &a, const query &b)
  15. { return a.l/sqr != b.l/sqr ? a.l < b.l : a.r < b.r; }
  16. } q[MAXN];
  17. bool cmp(const query &a, const query &b)
  18. { return a.id < b.id; }
  19. int a[MAXN], tmp[30];
  20. unsigned long long d[MAXN], dx[MAXN], qu[MAXN], top = 0;
  21. void dx_init()
  22. {
  23. memcpy(dx, d, sizeof d);
  24. sort(dx+1, dx+top+1);
  25. }
  26. int dx_num(unsigned long long dat)
  27. { return lower_bound(dx+1, dx+top+1, dat)-dx; }
  28. int tab[MAXN];
  29. int main()
  30. {
  31. scanf("%d%d%d", &n, &m, &k), bas = n+1;
  32. sqr = sqrt(n); // 分块大小
  33. for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
  34. for (int i = 1; i+k-1 <= n; i++) d[++top] = hash_val(a, i, i+k-1);
  35. for (int i = 1; i <= m; i++) {
  36. scanf("%d%d", &q[i].l, &q[i].r); q[i].r = q[i].r-k+1;
  37. for (int j = 1; j <= k; j++) scanf("%d", &tmp[j]);
  38. qu[i] = hash_val(tmp, 1, k);
  39. d[++top] = qu[i], q[i].id = i;
  40. }
  41. dx_init(); // 离散化
  42. for (int i = 1; i+k-1 <= n; i++) a[i] = dx_num(d[i]);
  43. for (int i = 1; i <= m; i++) q[i].dat = dx_num(qu[i]);
  44. sort(q+1, q+m+1);
  45. memset(tab, 0, sizeof tab);
  46. int L = q[1].l, R = q[1].r;
  47. for (int i = L; i <= R; i++) tab[a[i]]++; q[1].ans = tab[q[1].dat];
  48. for (int i = 2; i <= m; i++) {
  49. if (q[i].l > q[i].r) continue;
  50. while (L < q[i].l) tab[a[L++]]--;
  51. while (L > q[i].l) tab[a[--L]]++;
  52. while (R < q[i].r) tab[a[++R]]++;
  53. while (R > q[i].r) tab[a[R--]]--;
  54. q[i].ans = tab[q[i].dat];
  55. }
  56. sort(q+1, q+m+1, cmp);
  57. for (int i = 1; i <= m; i++)
  58. if (q[i].ans) puts("No");
  59. else puts("Yes");
  60. return 0;
  61. }

bzoj1103: [POI2007]大都市meg

看题解dfs序+树状数组就水过去了,O(nlgn)
但是写了链剖O(nlg2n)也水过去了。
然而O(nlgn)的lct却死超死超的...
玄学啊...当然也可能我写跪了...

链剖

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 250005;
  4. int C[MAXN], n, dstop = 0;
  5. int lowbit(int i) { return i&(-i); }
  6. void modify(int pos, int dt)
  7. { for (int i = pos; i <= n; i += lowbit(i)) C[i] += dt; }
  8. int sum(int pos)
  9. {
  10. int ans = 0;
  11. for (int i = pos; i > 0; i -= lowbit(i)) { ans += C[i];}
  12. return ans;
  13. }
  14. int sum(int l, int r)
  15. { return sum(r)-sum(l-1); }
  16. struct node {
  17. int to, next;
  18. } edge[MAXN*2];
  19. int head[MAXN], top;
  20. void push(int i, int j)
  21. { ++top, edge[top] = (node){j, head[i]}, head[i] = top; }
  22. int siz[MAXN], id[MAXN], ind[MAXN], fa[MAXN];
  23. void dfs1(int nd)
  24. {
  25. siz[nd] = 1;
  26. for (int i = head[nd]; i; i = edge[i].next)
  27. dfs1(edge[i].to), siz[nd] += siz[edge[i].to], fa[edge[i].to] = nd;
  28. }
  29. void dfs2(int nd, int from = 0)
  30. {
  31. id[nd] = ++dstop, ind[nd] = from, modify(id[nd], 1);
  32. int hev = 0;
  33. for (int i = head[nd]; i; i = edge[i].next)
  34. if (siz[edge[i].to] > siz[hev])
  35. hev = edge[i].to;
  36. if (!hev) return;
  37. dfs2(hev, from);
  38. for (int i = head[nd]; i; i = edge[i].next)
  39. if (edge[i].to != hev)
  40. dfs2(edge[i].to, edge[i].to);
  41. }
  42. void change(int nd)
  43. { modify(id[nd], -1); }
  44. int ask(int nd)
  45. {
  46. int ans = 0;
  47. while (nd) {
  48. // cout << nd << endl;
  49. ans += sum(id[ind[nd]], id[nd]), nd = fa[ind[nd]];
  50. }
  51. return ans;
  52. }
  53. int main()
  54. {
  55. scanf("%d", &n);
  56. for (int i = 1; i < n; i++) {
  57. int u, v; scanf("%d%d", &u, &v);
  58. if (u > v) swap(u,v);
  59. push(u, v);
  60. }
  61. dfs1(1), dfs2(1);
  62. int m; scanf("%d", &m);
  63. for (int i = 1; i <= m+n-1; i++) {
  64. char s; int u, v;
  65. scanf("\n%c", &s);
  66. if (s == 'A') { scanf("%d%d", &u, &v), change(max(u,v)); }
  67. else if (s == 'W') {scanf("%d", &u), printf("%d\n", ask(u)-1); }
  68. else throw;
  69. }
  70. return 0;
  71. }

LCT(TLE)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 250005;
  4. int chl[MAXN][2], dat[MAXN], hv[MAXN], stk[MAXN], stktop = 0, fa[MAXN];
  5. int rev[MAXN], n, m;
  6. bool is_rt(int nd)
  7. { return nd != chl[fa[nd]][0] && nd != chl[fa[nd]][1]; }
  8. void update(int nd)
  9. { dat[nd] = dat[chl[nd][0]] + dat[chl[nd][1]] + hv[nd];}
  10. void pdw(int nd)
  11. {
  12. if (!rev[nd]) return;
  13. int &lc = chl[nd][0], &rc = chl[nd][1]; rev[nd] = 0;
  14. if (lc) rev[lc] ^= 1;
  15. if (rc) rev[rc] ^= 1;
  16. swap(lc, rc);
  17. }
  18. void zig(int nd)
  19. {
  20. int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
  21. int son = chl[nd][tp^1];
  22. if (!is_rt(p)) chl[g][tg] = nd; chl[nd][tp^1] = p, chl[p][tp] = son;
  23. fa[son] = p, fa[p] = nd, fa[nd] = g;
  24. update(p), update(nd);
  25. }
  26. void splay(int nd)
  27. {
  28. stk[stktop = 1] = nd;
  29. for (int i = nd; !is_rt(i); i = fa[i]) stk[++stktop] = fa[i];
  30. while (stktop) pdw(stk[stktop--]);
  31. while (!is_rt(nd)) {
  32. int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
  33. if (is_rt(p)) { zig(nd); break; }
  34. else if (tp == tg) zig(p), zig(nd);
  35. else zig(nd), zig(nd);
  36. }
  37. }
  38. void access(int x)
  39. {
  40. for (int y = 0; x; x = fa[y = x])
  41. splay(x), chl[x][1] = y, update(x);
  42. }
  43. void make_rt(int x)
  44. { access(x), splay(x), rev[x] ^= 1; }
  45. void link(int i, int j)
  46. { make_rt(j), fa[j] = i, access(j); }
  47. void change(int nd)
  48. { make_rt(nd), splay(nd), hv[nd]--, update(nd); }
  49. int ask(int nd)
  50. { make_rt(1), access(nd), splay(nd); return hv[nd]+dat[chl[nd][0]]; }
  51. int main()
  52. {
  53. scanf("%d", &n);
  54. for (int i = 2; i <= n; i++) hv[i] = 1;
  55. for (int i = 1; i < n; i++) {
  56. int u, v; scanf("%d%d", &u, &v);
  57. if (u > v) swap(u, v);
  58. link(u, v);
  59. }
  60. scanf("%d", &m);
  61. for (int i = 1; i <= n+m-1; i++) {
  62. char c; int u, v;
  63. scanf("\n%c", &c);
  64. if (c == 'W') { scanf("%d", &u), printf("%d\n", ask(u)); }
  65. else if (c == 'A') { scanf("%d%d", &u, &v), change(max(u, v)); }
  66. }
  67. return 0;
  68. }

dfn&BIT

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 250005;
  4. int C[MAXN], n, dstop = 0;
  5. int lowbit(int i) { return i&(-i); }
  6. void modify(int pos, int dt)
  7. { for (int i = pos; i <= n; i += lowbit(i)) C[i] += dt; }
  8. int sum(int pos)
  9. {
  10. int ans = 0;
  11. for (int i = pos; i > 0; i -= lowbit(i)) { ans += C[i];}
  12. return ans;
  13. }
  14. struct node {
  15. int to, next;
  16. } edge[MAXN];
  17. int head[MAXN], top = 0;
  18. void push(int i, int j)
  19. { ++top, edge[top] = (node){j, head[i]}, head[i] = top; }
  20. int depth[MAXN], dfi[MAXN], dfo[MAXN], dft = 0;
  21. void dfs(int nd)
  22. {
  23. dfi[nd] = ++dft;
  24. for (int i = head[nd]; i; i = edge[i].next) {
  25. int to = edge[i].to;
  26. depth[to] = depth[nd]+1;
  27. dfs(to);
  28. }
  29. dfo[nd] = dft;
  30. }
  31. void change(int nd)
  32. { modify(dfi[nd], 1), modify(dfo[nd]+1, -1); }
  33. int ask(int nd)
  34. { return depth[nd]-sum(dfi[nd]); }
  35. int main()
  36. {
  37. scanf("%d", &n);
  38. for (int i = 1; i < n; i++) {
  39. int u, v; scanf("%d%d", &u, &v);
  40. if (u > v) swap(u,v);
  41. push(u, v);
  42. }
  43. depth[1] = 0, dfs(1);
  44. int m; scanf("%d", &m);
  45. for (int i = 1; i <= n+m-1; i++) {
  46. char s; int u, v;
  47. scanf("\n%c", &s);
  48. if (s == 'A') { scanf("%d%d", &u, &v), change(max(u,v)); }
  49. else if (s == 'W') {scanf("%d", &u), printf("%d\n", ask(u)); }
  50. else throw;
  51. }
  52. return 0;
  53. }

4.13

bzoj3506: [Cqoi2014]排序机械臂

题面传送门

就是splay维护最小值和最小值位置,加上反转操作即可。
然而debug能力是硬伤...
注意重复元素的处理,就是xixi(n+1)+i

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005;
  4. int chl[MAXN][2], fa[MAXN], rev[MAXN], stk[MAXN], stktop = 0;
  5. int top = 0, min_pos[MAXN], siz[MAXN], root = 0;
  6. long long min_val[MAXN], dat[MAXN];
  7. void update(int nd)
  8. {
  9. min_val[nd] = min(dat[nd], min(min_val[chl[nd][0]], min_val[chl[nd][1]]));
  10. min_pos[nd] = min_val[nd] == min_val[chl[nd][0]] ? min_pos[chl[nd][0]] : (min_val[nd] == dat[nd] ? nd : min_pos[chl[nd][1]]);
  11. siz[nd] = siz[chl[nd][0]] + siz[chl[nd][1]] + 1;
  12. }
  13. inline int new_node(long long d) { return ++top, dat[top] = d, update(top), top;}
  14. void pdw(int nd)
  15. {
  16. if (!rev[nd]) return;
  17. int &lc = chl[nd][0], &rc = chl[nd][1];
  18. if (lc) rev[lc] ^= 1;
  19. if (rc) rev[rc] ^= 1;
  20. swap(lc, rc), rev[nd] ^= 1;
  21. }
  22. void zig(int nd)
  23. {
  24. int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
  25. int son = chl[nd][tp^1];
  26. fa[son] = son==0?0:p, fa[p] = nd, fa[nd] = g;
  27. chl[g][tg] = g==0?0:nd, chl[nd][tp^1] = p, chl[p][tp] = son;
  28. root = g?root:nd;
  29. update(p), update(nd);
  30. }
  31. void splay(int nd, int tar = 0)
  32. {
  33. stk[stktop = 1] = nd;
  34. for (int i = nd; fa[i]; i = fa[i]) stk[++stktop] = fa[i];
  35. for (; stktop; stktop--) pdw(stk[stktop]);
  36. while (fa[nd] != tar) {
  37. int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
  38. if (g == tar) {zig(nd); break; }
  39. else if (tp == tg) zig(p), zig(nd);
  40. else zig(nd), zig(nd);
  41. }
  42. }
  43. void dfs(int nd)
  44. {
  45. if (!nd) return;
  46. pdw(nd);
  47. dfs(chl[nd][0]);
  48. cerr << dat[nd] << " ";
  49. dfs(chl[nd][1]);
  50. }
  51. void insert(long long nd)
  52. {
  53. if (root == 0) root = new_node(nd);
  54. else {
  55. chl[root][1] = new_node(nd), fa[top] = root;
  56. splay(top), update(top);
  57. // dfs(top);
  58. }
  59. }
  60. int get_min()
  61. {
  62. splay(min_pos[root]);
  63. int ans = siz[chl[root][0]]+1;
  64. return ans;
  65. }
  66. int get_by_order(int k)
  67. {
  68. int nd = root; k--; // have k element on left
  69. while (nd) {
  70. pdw(nd), update(nd);
  71. if (siz[chl[nd][0]] == k) break;
  72. nd = siz[chl[nd][0]]>k?chl[nd][0]:(k -= siz[chl[nd][0]]+1, chl[nd][1]);
  73. }
  74. return nd;
  75. }
  76. int get_segment(int l, int r)
  77. {
  78. if (l == 1 && r == siz[root]) return root;
  79. if (l == 1) return splay(get_by_order(r+1)), chl[root][0];
  80. if (r == siz[root]) return splay(get_by_order(l-1)), chl[root][1];
  81. return splay(get_by_order(l-1)), splay(get_by_order(r+1), root), chl[chl[root][1]][0];
  82. }
  83. void del_root()
  84. {
  85. int t = get_segment(siz[chl[root][0]]+1, siz[chl[root][0]]+1);
  86. int tp = chl[fa[t]][0] != t; chl[fa[t]][tp] = 0;
  87. for (int i = fa[t]; i; i = fa[i]) update(i);
  88. fa[t] = 0;
  89. }
  90. void reverse(int l, int r)
  91. {
  92. int t = get_segment(l, r);
  93. rev[t] ^= 1;
  94. }
  95. int ans()
  96. {
  97. int ret = get_min();
  98. reverse(1, ret);
  99. splay(min_pos[root]), del_root();
  100. return ret;
  101. }
  102. int n;
  103. int main()
  104. {
  105. memset(min_val, 127/3, sizeof min_val);
  106. scanf("%d", &n);
  107. for (int i = 1; i <= n; i++) {
  108. int u; scanf("%d", &u); insert((long long)u*(n+1)+i);
  109. }
  110. for (int i = 1; i <= n; i++) printf("%d ", ans()+i-1);
  111. return 0;
  112. }

bzoj3530: [Sdoi2014]数数

大爷题解:http://blog.csdn.net/aarongzk/article/details/50472209#

就是AC自动机上dp,然而数位dp仍然跪烂...要注意前导零的处理。
AC自动机忘记push儿子调试1h...

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXL = 1505;
  4. int vis[MAXL];
  5. struct ACM {
  6. struct node {
  7. int chl[10];
  8. int finished, fail;
  9. node() { memset(chl, 0, sizeof chl), finished = fail = 0; }
  10. } tree[MAXL];
  11. int top, root;
  12. ACM() { top = root = 0; }
  13. inline int new_node() { return ++top; }
  14. void insert(int &nd, const char *str)
  15. {
  16. if (!nd) nd = new_node();
  17. if (*str == '\0') tree[nd].finished = 1, vis[nd] = 1;
  18. else insert(tree[nd].chl[*str-'0'], str+1);
  19. }
  20. queue<int> que;
  21. void init()
  22. {
  23. tree[root].fail = 0, que.push(root);
  24. while (!que.empty()) {
  25. int nd = que.front(); que.pop(); vis[nd] |= vis[tree[nd].fail];
  26. for (int i = 0; i < 10; i++) {
  27. if (!tree[nd].chl[i]) continue;
  28. int p = tree[nd].fail;
  29. while (p && !tree[p].chl[i]) p = tree[p].fail;
  30. if (!p) tree[tree[nd].chl[i]].fail = root;
  31. else tree[tree[nd].chl[i]].fail = tree[p].chl[i];
  32. que.push(tree[nd].chl[i]);
  33. }
  34. } ;
  35. }
  36. int trans(int nd, int ths)
  37. {
  38. if (tree[nd].chl[ths]) return tree[nd].chl[ths];
  39. int p = tree[nd].fail;
  40. while (p && !tree[p].chl[ths]) p = tree[p].fail;
  41. if (!p) return root;
  42. else return tree[p].chl[ths];
  43. }
  44. } ac;
  45. long long dp[1500][MAXL][3]; // 1 随意 0 不随意
  46. char str[MAXL]; int s[MAXL];
  47. long long mod = 1e9+7;
  48. int n, m;
  49. int main()
  50. {
  51. memset(vis, 0, sizeof vis);
  52. scanf("%s", str+1); n = strlen(str+1);
  53. for (int i = 1; i <= n; i++) s[i] = str[i]-'0';
  54. scanf("%d", &m);
  55. for (int i = 1; i <= m; i++) {
  56. scanf("%s", str);
  57. ac.insert(ac.root, str);
  58. }
  59. long long ans = 0;
  60. ac.init();
  61. memset(dp, 0, sizeof dp);
  62. for (int i = 1; i < 10; i++) if (!vis[ac.trans(ac.root, i)]) dp[2][ac.trans(ac.root, i)][0]++;
  63. for (int i = 2; i < n; i++)
  64. for (int j = 1; j <= ac.top; j++)
  65. for (int k = 0; k < 10; k++) if (!vis[ac.trans(j, k)])
  66. (dp[i+1][ac.trans(j, k)][0] += dp[i][j][0]) %= mod;
  67. for (int i = 2; i <= n; i++)
  68. for (int j = 1; j <= ac.top; j++)
  69. (ans += dp[i][j][0]) %= mod; // 前导0
  70. memset(dp, 0, sizeof dp);
  71. for (int i = 1; i <= s[1]; i++)
  72. if (!vis[ac.trans(ac.root, i)])
  73. dp[2][ac.trans(ac.root, i)][i == s[1]]++;
  74. for (int i = 2; i <= n; i++) {
  75. for (int j = 1; j <= ac.top; j++)
  76. for (int k = 0; k < 10; k++) {
  77. if (vis[ac.trans(j, k)]) continue;
  78. (dp[i+1][ac.trans(j, k)][0] += dp[i][j][0]) %= mod;
  79. if (k < s[i]) (dp[i+1][ac.trans(j, k)][0] += dp[i][j][1]) %= mod;
  80. else if (k == s[i]) (dp[i+1][ac.trans(j, k)][1] += dp[i][j][1]) %= mod;
  81. }
  82. }
  83. for (int i = 1; i <= ac.top; i++)
  84. (ans += dp[n+1][i][0]+dp[n+1][i][1]) %= mod;
  85. cout << ans << endl;
  86. return 0;
  87. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注